Audiobooks: free audiobooks from LibriVox (search, shelf, chapters, synced listening position)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaC9HmtHMdRP8dAbN4wAKj
This commit is contained in:
10 files changed
+212
-5
No files matched your search
@@ -67,7 +67,7 @@ async function viewBooks(args = []) {
|
||||
abBooks = Array.isArray(data) ? data : (data.books || Object.values(data));
|
||||
} catch (e) {
|
||||
if (!location.hash.startsWith('#/audio')) return;
|
||||
v.innerHTML = `<div class="wrap"><h1>Audiobooks</h1><p class="err">${esc(e.message)}</p><div class="bar"><button class="btn ghost" id="abretry">Try again</button><a class="btn ghost" href="#/settings">Settings</a><a class="btn ghost" href="#/audio/classic">Open the classic player</a></div></div>`;
|
||||
v.innerHTML = `<div class="wrap"><h1>Audiobooks</h1><p class="err">${esc(e.message)}</p><div class="bar"><button class="btn ghost" id="abretry">Try again</button><a class="btn ghost" href="#/audio/free">Free audiobooks</a><a class="btn ghost" href="#/settings">Settings</a><a class="btn ghost" href="#/audio/classic">Open the classic player</a></div></div>`;
|
||||
$('#abretry').onclick = () => route(); return;
|
||||
}
|
||||
if (!location.hash.startsWith('#/audio')) return;
|
||||
@@ -76,7 +76,7 @@ async function viewBooks(args = []) {
|
||||
<span class="vimg" style="aspect-ratio:1/1;background:linear-gradient(135deg,hsl(${abHue(abTitle(b))} 55% 40%),hsl(${abHue(abTitle(b)) + 40} 55% 28%))"><img loading="lazy" alt="" src="${abCover(b)}" onerror="this.remove()">${pct(b) > 1 ? `<i class="vprog"><b style="width:${pct(b)}%"></b></i>` : ''}</span>
|
||||
<b>${esc(abTitle(b))}</b><small>${esc(abAuthor(b))}</small></button>`;
|
||||
const cont = abBooks.filter(b => { const p = abProg[abId(b)]; return p && p.pos > 10 && p.dur && p.pos < p.dur - 30; }).sort((a, b) => abProg[abId(b)].t - abProg[abId(a)].t).slice(0, 10);
|
||||
v.innerHTML = `<div class="wrap"><div class="ptop"><h1>Audiobooks</h1><span class="pspace grow"></span><a class="btn ghost" href="#/audio/classic" title="The audiobook player's own page">Classic player</a></div>
|
||||
v.innerHTML = `<div class="wrap"><div class="ptop"><h1>Audiobooks</h1><span class="pspace grow"></span><a class="btn ghost" href="#/audio/free">Free audiobooks</a><a class="btn ghost" href="#/audio/classic" title="The audiobook player's own page">Classic player</a></div>
|
||||
${cont.length ? `<h2>Continue listening</h2><div class="vrow">${cont.map(b => card(b, true)).join('')}</div>` : ''}
|
||||
<input type="search" id="abq" placeholder="Search your books" autocomplete="off" autocapitalize="off" style="margin-top:14px">
|
||||
<h2>Library</h2><div class="vgrid" id="abgrid"></div></div>`;
|
||||
|
||||
Reference in new issue
Block a user