diff --git a/static/js/app.js b/static/js/app.js index 23dbcf1..b3a76ac 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2611,13 +2611,15 @@ async function loadBookList() { listEl.innerHTML = '

Loading…

'; try { - const res = await fetch('/books/'); + const res = await fetch('/books/', {cache: 'no-store'}); if (!res.ok) { + console.error('loadBookList: server returned', res.status); listEl.innerHTML = `

Server error ${res.status} loading books.

`; return; } const books = await res.json(); if (!Array.isArray(books)) { + console.error('loadBookList: unexpected response', books); listEl.innerHTML = `

Unexpected response from server.

`; return; } @@ -2626,22 +2628,32 @@ async function loadBookList() { return; } - const key = await getOrCreateEncKey(); + let key; + try { + key = await getOrCreateEncKey(); + } catch (e) { + console.error('loadBookList: getOrCreateEncKey failed', e); + listEl.innerHTML = `

Encryption not available: ${e.message}. Make sure you are on HTTPS.

`; + return; + } + const decrypted = []; for (const b of books) { try { const metaBuf = await decryptBytes(key, b.meta_iv, b.meta_ct); const meta = JSON.parse(new TextDecoder().decode(metaBuf)); bookMetaCache[b.id] = {title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub'}; - decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at}); + decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: true}); } catch (e) { + console.warn(`loadBookList: could not decrypt book #${b.id}:`, e.message); bookMetaCache[b.id] = {title: `Book #${b.id}`, author: '', type: 'epub'}; - decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at}); + decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: false}); } } renderBookList(decrypted); } catch (e) { - if (listEl) listEl.innerHTML = `

Error: ${e.message}

`; + console.error('loadBookList error:', e); + if (listEl) listEl.innerHTML = `

Error loading books: ${e.message}

`; } } @@ -2651,14 +2663,15 @@ function renderBookList(books) { let html = ''; for (const b of books) { const pct = Math.round((b.scroll_fraction || 0) * 100); + const keyWarning = b.keyOk === false ? '⚠️ wrong key' : ''; html += `
- ${escapeHtml(b.title)} + ${escapeHtml(b.title)}${keyWarning} ${escapeHtml(b.author)} ${pct > 0 ? `${pct}% read` : ''}
- +
`; @@ -3076,7 +3089,8 @@ async function openBook(bookId) { } } catch (e) { - contentEl.innerHTML = `

Failed to open book: ${escapeHtml(e.message)}

`; + overlay.style.display = 'none'; + alert(`Failed to open book: ${e.message}`); } }