Commit graph

98 commits

Author SHA1 Message Date
marwin
2d488fd542 EPUB reader: font picker + performance fixes for large books
All checks were successful
Build and push Docker image / build (push) Successful in 1m17s
Test / test (push) Successful in 14s
- Add font family selector (Serif/Sans/Verdana/Mono) to reader settings panel,
  saved per book in localStorage
- Strip <style>/<script> blocks before regex and DOMParser processing to avoid
  working over large base64-embedded font CSS in publisher EPUBs
- Parallelize image blob URL creation with Promise.all instead of sequential await
- Inject chapter HTML progressively in batches with requestAnimationFrame yields
  to keep the UI responsive when loading many-chapter books

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 11:40:58 +02:00
marwin
9241d6170b Remove loading overlay from re-renders (zoom/spread)
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Current page renders almost instantly, no overlay needed.
Overlay stays for initial book open only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:55:13 +02:00
marwin
1cf3f730ea Render PDF from current page outward on zoom/re-render
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
renderPdf now takes an optional pivotPage. Pass 1 builds the full DOM
and sizes all canvases (instant). Then scrolls to the pivot page
immediately so the user stays in place. Pass 2 renders pixels from
pivot→end, then pivot-1→start.

reRenderPdf detects the current visible page before re-rendering and
passes it as pivot, so zoom no longer resets scroll position.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:50:01 +02:00
marwin
20a1b9a889 Fix scroll position lost after PDF zoom re-render
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Scroll position was restored before browser finished layout, so
scrollHeight was still wrong. Now waits two animation frames after
reRenderPdf completes before restoring position.

Also shows loading overlay during zoom re-renders, not just on initial load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:44:49 +02:00
marwin
89cb70392a j/k scroll continuously while held, stop on keyup
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Uses a 16ms interval (~60fps) instead of per-event smooth scroll,
so holding j/k scrolls fluidly. d/u/f/b remain one-shot with smooth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:32:32 +02:00
marwin
b6619f6465 Fix PDF loading overlay disappearing too early
All checks were successful
Test / test (push) Successful in 18s
Build and push Docker image / build (push) Successful in 14s
Moved overlay out of contentEl (which renderPdf clears immediately)
into the reader-overlay element. It now stays visible for the entire
render duration and is removed only after renderPdf resolves.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:29:46 +02:00
marwin
d607388bad Add vim-style keyboard shortcuts to reader
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 17s
j/k    scroll down/up (small step, ~8% viewport)
d/u    scroll half page down/up
f/b    scroll full page down/up
g/G    jump to top/bottom
n/p    next/prev page (PDF scroll mode)

Keys are ignored when an input or textarea is focused.
Existing arrow key navigation in paginated PDF mode unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:20:06 +02:00
marwin
bbb982d0b1 PDF loading overlay: dark translucent instead of solid black
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:09:52 +02:00
marwin
846b299713 Show dark loading overlay while PDF is rendering
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
Displays a dark background with a spinning indicator in the reader
content area before renderPdf starts. renderPdf clears innerHTML
itself when it begins, so no explicit cleanup needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:08:44 +02:00
marwin
d839a8f8a3 Dark scrollbar styling
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:06:20 +02:00
marwin
1fdf5f9b30 Remove double scrollbar in Chrome PWA
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
html/body no longer scroll — overflow: hidden on both.
.main-content gets height: calc(100% - nav-h) and overflow-y: auto
so it's the single scroll container. The reader overlay is
position: fixed so it's unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:01:23 +02:00
marwin
8a3aedb0e7 Use Window Controls Overlay for Chrome PWA titlebar
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
Adds display_override: window-controls-overlay to the manifest so
the app extends into the titlebar area. The navbar becomes draggable
and uses env(titlebar-area-*) to avoid the window controls buttons.
Interactive elements stay clickable via -webkit-app-region: no-drag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 17:54:00 +02:00
marwin
def879de2d Fix radio sidebar play buttons broken by JSON.stringify double quotes
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Inline onclick='playStation("url", "name", null)' broke because
JSON.stringify wraps strings in double quotes, conflicting with the
onclick attribute quotes. Replaced with data attributes + addEventListener.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 17:32:05 +02:00
marwin
f5c141626f Fix blurry PDF rendering when zoomed in Chrome PWA
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
Zoom is now baked into the canvas render scale instead of being applied
via CSS zoom. CSS zoom only scales pixels already on the canvas, causing
blurriness at high DPR (e.g. PWA on mobile). Now the canvas is rendered
at the correct resolution for the chosen zoom level.

Also: stop nulling currentPdfDoc on re-render so PDF.js page cache is
preserved, making zoom re-renders significantly faster.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 16:14:24 +02:00
marwin
e5dc58d84f Replace focus station sidebar with compact radio player sidebar
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
The 📻 button now opens a sidebar with the currently playing station/track,
play/stop + volume control, and the saved stations list. The old focus
station configuration UI (presets, custom URL input, save-to-server) and
the auto-play-on-book-open behavior are removed.

Closes #6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:22:07 +02:00
marwin
554ca93e30 Close reader settings panel when tapping content to hide bars
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:13:28 +02:00
marwin
6b419c6fe0 Save reader settings per book in localStorage
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
Each book gets its own key (diora_reader_settings_{bookId}).
Opening a book resets to defaults then applies book-specific overrides,
so zoom, spread, invert, theme etc. are remembered independently per book.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:53:38 +02:00
marwin
916e8a568b Add PDF two-page spread mode and mobile pinch-to-zoom
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Spread mode: new toggle in reader settings renders pages side-by-side
(cover alone, then pairs 2-3, 4-5...) using full screen width. Each
page scales to half the container. Navigation and scroll position
tracking are unchanged since per-page IDs are preserved.

Pinch-to-zoom: captures 2-finger pinch on the PDF reader, blocking
native browser zoom. Live CSS zoom during gesture, snaps to nearest
10% step on release. Single-finger scroll unaffected. applyPdfZoom
moved to module level so touch handlers can call it. Touch listeners
cleaned up on reader close.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:18:25 +02:00
marwin
e9c5b8058b Centralize remaining magic numbers in settings.py
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
- HIGHLIGHTS_MAX_BYTES, BOOKMARKS_MAX_BYTES: books size limits now in settings
- PODCAST_INBOX_PAGE_SIZE: shared between podcasts/views.py and app.js via DIORA_CONFIG
- VOLUME_DEFAULT: radio stream player default volume
- ITUNES_TIMEOUT: unified iTunes API timeout (was 5s vs 6s inconsistency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:10:14 +02:00
marwin
0a6ba6feac Inject upload size limits from settings into frontend via DIORA_CONFIG
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Backend settings are now the single source of truth for EBOOK_MAX_BYTES
and BG_MAX_BYTES. A new context processor exposes them to all templates,
and base.html injects them as window.DIORA_CONFIG so app.js reads from
there instead of hardcoded values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:05:51 +02:00
marwin
9c0a046c57 Fix ebook upload: new books appear at top, 50 MB limit frontend/backend
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
- Create EBookProgress on upload so new books get a last_read timestamp
  and sort to the top of the book list
- Update frontend file size check from 10 MB to 50 MB
- Fix backend error message to say 50 MB instead of 10 MB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:01:32 +02:00
marwin
4274f49971 Increased ebook upload limit to 50 MB
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
2026-04-04 20:48:18 +02:00
marwin
2ba613fdd8 Reconnect audio automatically on device change
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
Listens for navigator.mediaDevices.devicechange and re-routes the
audio element to the new default output device without a page reload.
Debounced 500ms to handle BT device bursts. Podcasts resume at the
correct timestamp via loadedmetadata.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 02:27:18 +02:00
marwin
aff4f5aef2 Mobile: hide volume, add PDF zoom +/- buttons, fix zoom scroll position
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
- Hide volume label/slider/input on mobile (≤600px)
- Add − and + buttons flanking the PDF zoom slider
- Preserve scroll fraction across zoom changes in PDF scroll mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 12:22:04 +02:00
marwin
1bda59e3fc Fix PDF position restore: timer after restore, add scroll-mode case
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- Move auto-save timer setup to after position restore so an early
  visibilitychange can't overwrite the saved position with 0
- Add missing restore path for non-paginated PDF scroll mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:46:57 +02:00
marwin
68bb7b5920 Add IndexedDB book cache and fix PDF position on mobile
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
- Cache encrypted book data in IndexedDB (cache-first on open)
- Evict books not read for 4 weeks on book list load
- Fix PDF paginated mode not activating on book open (mobile)
- enterPdfPaginatedMode() now called after position restore in openBook()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 16:10:03 +02:00
marwin
dbe3b46f3e Simplify immersive reader: tap centre to toggle bars
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Replace timer/edge-hover system with a simple click-to-toggle.
Tapping interactive elements (buttons, links, settings) is ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:50:31 +02:00
marwin
2448586050 Fix PDF rendering blur on high-DPI/mobile screens
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 14s
Scale canvas by devicePixelRatio and constrain CSS size to logical
pixels so PDF pages render crisp on Retina and mobile displays.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:48:44 +02:00
marwin
1af07c7952 Add anchor-based reading position tracking
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Replaces scroll_fraction-only position tracking with element-based
anchors ("{index}:{innerFraction}"). Position is now stable across
font size changes and different screen sizes. A ResizeObserver
restores the anchor on viewport/orientation changes.

Falls back to scroll_fraction for books without a saved anchor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:41:30 +02:00
marwin
0c6846e71f Give navbar and now-playing-bar solid background
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:24:35 +02:00
marwin
bef8fbc8d8 Revert "Remove immersive reader mode, bars stay always visible"
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
This reverts commit bdb6857c73.
2026-04-01 15:24:00 +02:00
marwin
bdb6857c73 Remove immersive reader mode, bars stay always visible
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:23:10 +02:00
marwin
44d51d3a7f Fix gpodder: add update_urls to episode actions POST response
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
AntennaPod's GpodnetEpisodeActionPostResponse expects update_urls
in the episode upload response, not just timestamp.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 19:08:46 +01:00
marwin
a205eafd79 Fix gpodder sync: return update_urls in subscription GET response
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
AntennaPod throws JSONException when update_urls is missing from the
subscription list response. Return the change-format object instead
of a plain array for GET requests without a since parameter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 17:15:36 +01:00
marwin
2859464b14 Open HTTP streams in new tab to bypass mixed content
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 11:45:40 +01:00
marwin
da300b54c7 Revert: remove HTTP stream new-tab workaround
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 10:54:48 +01:00
marwin
f040a45325 Open HTTP streams in raw new tab instead of custom HTTPS player
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 14s
The custom /radio/stream-player/ page is served over HTTPS, so the browser
still applies mixed-content restrictions and upgrades http:// audio to https://,
which fails for streams without TLS support.

Fix: window.open(url, '_blank') navigates the tab directly to the HTTP URL.
The tab itself is then HTTP, bypassing mixed-content restrictions entirely.
Browser plays the stream natively with its built-in audio player.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 10:48:28 +01:00
marwin
9e08079dec Fix stream player autoplay: handle blocked play() promise
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 17s
window.open() doesn't transfer the user gesture to the new tab, so autoplay
is blocked. Previously play().catch(()=>{}) swallowed the error silently while
setting playing=true, leaving the UI in a broken state.

Now: if play() rejects, reset state and show "Click Play to start". The user's
click on the Play button IS a user gesture, so it succeeds on the second attempt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 10:39:43 +01:00
marwin
ee8cfd8314 Fix immersive reader: extend top zone to cover visible bar heights
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
When top bars are showing, use their actual combined offsetHeight (+12px buffer)
as the hide threshold instead of the fixed 60px. This prevents the bars from
disappearing while the mouse moves from the edge zone down to click header buttons.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 19:01:37 +01:00
marwin
0037fd8db4 Reader immersive mode: bars slide out after 5s, return on edge hover/tap
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
After opening a book, a 5-second timer adds body.reader-immersive which:
- Slides navbar up (translateY(-100%))
- Slides now-playing bar down (translateY(100%))
- Expands reader overlay to full viewport (top:0, bottom:0)
- Collapses reader header (max-height:0)

Mouse near top edge (<60px): shows navbar + reader header
Mouse near bottom edge (<60px): shows now-playing bar
Touch at top/bottom edge: shows respective bar for 3s then hides again
closeReader() cleans up all classes and event listeners

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 18:04:11 +01:00
marwin
85776390f6 Open HTTP streams in minimal standalone player tab
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Instead of trying a HTTPS upgrade (which fails for IP-based streams):
- playStation() detects http:// URL on https:// page, opens /radio/stream-player/
  with url, name, vol as query params, then returns — main stream is already
  stopped by the stopPlayback(false) call at the top of playStation()
- New view stream_player renders a standalone minimal player page
- Template: auto-plays on load, correct volume from URL param, volume changes
  synced back to localStorage so main window picks it up next time,
  live track metadata via SSE, tab title updates on track change,
  close-tab button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:50:12 +01:00
marwin
83304c197d Try HTTPS upgrade for HTTP streams, show error on failure
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Browsers block HTTP (mixed content) audio from HTTPS pages. On playStation,
if the URL is http:// and page is https://, try the https:// version first.
If the stream fails to load, show a clear error in the track display instead
of silently doing nothing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:22:51 +01:00
marwin
38451514c2 Remove text marking and PDF pagination from master (moved to testing branch)
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
- Remove mouseup highlight selection listener
- Remove Paginated button from PDF settings panel
- Remove pagination auto-enable on book open

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:42:03 +01:00
marwin
7392bbcdcc Sort books by last read (most recently read first)
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
Backend includes last_read from EBookProgress.updated_at.
Frontend sorts by last_read desc, unread books by uploaded_at desc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:41:13 +01:00
marwin
1026ed09a7 PDF zoom: use CSS zoom instead of re-render, abort stale renders
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
- Add render generation counter (_pdfRenderGen) to abort overlapping renders
- Wrap all pages in #pdf-viewport div; zoom slider just updates style.zoom
- Use 'input' event on zoom slider for live preview without re-rendering
- enterPdfPaginatedMode resets viewport zoom to 1; exitPdfPaginatedMode restores it
- Remove pdfZoom factor from renderPdf scale (CSS zoom handles it now)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:22:11 +01:00
marwin
1cba67b3ed Fix PDF zoom: preserve buffer with slice(0), cap base width to 900px
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- Use arrayBuffer.slice(0) before passing to pdfjsLib.getDocument so PDF.js
  doesn't transfer/detach currentPdfBuffer, enabling re-renders on zoom change
- Cap containerWidth to min(viewport-32, 900px) so PDF doesn't stretch across
  the full viewport on wide screens

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:13:45 +01:00
marwin
04818c939e Fix PDF zoom in scroll and paginated mode
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- Remove max-width:100% from .pdf-page so canvas can exceed container width
- Override max-width:65ch on .pdf-page-wrapper (inherited from reader-content > *)
- Apply pdfZoom factor in pdfSmartZoomPage so paginated mode respects the zoom slider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:02:42 +01:00
Marwin Schulz
bb78afc569 Fix gPodder sync timeout: don't refresh feeds on subscription import
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
With 400 subscriptions, the initial sync POST was triggering 400
sequential RSS fetches in one request, causing a timeout/sync failure.
Feed metadata is populated by the cron job instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 13:20:34 +01:00
Marwin Schulz
a314643588 Fix JS crash: serialize saved_stations/featured_stations to proper JSON
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Python booleans (True/False) in saved_stations (is_favorite field) and
history (scrobbled field) were being rendered literally into JS via
|safe, causing 'True is not defined' ReferenceError that broke all JS
including book loading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:58:38 +01:00
Marwin Schulz
b0ce463cca Debug books: show visible status at each load stage, bump SW to v7
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Each step in loadBookList now updates the visible UI so the exact
failure point is obvious without opening DevTools.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:28:00 +01:00