Commit graph

78 commits

Author SHA1 Message Date
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
Marwin Schulz
dcef4736e6 Fix gPodder sync: add missing update_urls to subscription change responses
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 14s
AntennaPod throws JSONException when update_urls is absent from the
GET ?since=... subscription response. Added update_urls: [] to both
subscriptions_by_device and subscriptions_all delta responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:50:24 +01:00
Marwin Schulz
96a21f5482 Bump SW cache to v6 to force re-cache updated app.js/app.css
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 17s
Previous changes (renderBookList keyOk warning, openBook overlay fix)
were being served from the stale v5 cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:49:23 +01:00
Marwin Schulz
1649eb27a0 Fix ebooks: show wrong-key warning, close overlay on open failure
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- renderBookList now shows a ⚠️ warning and disables the Open button
  for books that couldn't be decrypted (keyOk: false), telling the user
  to import the correct encryption key
- openBook catch block now hides the reader overlay and shows an alert
  instead of leaving the overlay open with a cryptic error message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:45:39 +01:00
Marwin Schulz
4f413c673e Add 'Refresh all' button to podcast toolbar
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Shows live progress counter (↻ 3/42) while fetching feeds sequentially,
then reloads the current view when done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:18:38 +01:00
Marwin Schulz
74bebe6451 Fix cron container: switch dcron→cron, export env vars for cron jobs
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
- dcron doesn't support /etc/cron.d/ (vixie-cron format) — replace with
  standard 'cron' (vixie cron) which does
- Cron jobs run with a stripped environment and couldn't reach the database;
  fix by dumping Docker env vars to /etc/environment at startup and sourcing
  it in the cron job entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:16:29 +01:00
Marwin Schulz
fe4e1b5250 Move inbox 'Load more' button to bottom of list
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 14s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:13:47 +01:00
Marwin Schulz
f049c6ae66 Inbox/queue: clickable feed titles and episode titles
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 14s
- Feed title in inbox and queue is now a link that opens the feed's episode list
- Episode title in inbox is now clickable and opens the show notes sidebar
- Backend: include description in inbox API response so sidebar has content

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:12:36 +01:00
Marwin Schulz
afcbe087bb Replace 'recently refreshed' sort with 'most recent episode' in feed list
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Annotates feed queryset with Max(episodes__pub_date) so feeds are sorted
by when their latest episode was published, not when the feed was last fetched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:07:01 +01:00
Marwin Schulz
92801c9bbf Add podcast enhancements: AntennaPod parity features + inbox management
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- Auto-play next episode from queue when current episode ends
- Sleep timer (N minutes or end-of-episode) with countdown in button
- In-feed episode filter (client-side search)
- Auto-queue new episodes per feed (Q toggle, inserts at top of queue)
- More playback speeds: 1¾× and 2½× added
- Progress bars + structured meta line in all episode list views (feed, inbox, queue)
- Queue drag-and-drop reorder
- Feed list search filter and sort options (A–Z, Z–A, recently added/refreshed)
- DB migration: PodcastFeed.auto_queue, EpisodeProgress.dismissed
- Inbox: dismiss episodes without marking played, checkboxes for multi-select,
  bulk actions (add to queue, mark played, download, dismiss), load-more pagination
- Refresh button in single feed view header
- Hourly background refresh of all subscribed feeds
- Full Media Session API for radio and podcast: Windows taskbar thumbnail buttons
  (play/pause/stop/next/seek) now work correctly for both modes
- Playing an episode auto-adds it to the queue if not already there

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 08:55:11 +01:00
marwin
fe5dd3e58a Debug: show specific error in book list instead of generic message
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-20 06:43:36 +01:00
marwin
824b77a033 Add gPodder sync API and bump SW cache to v5
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 17s
- Implement gPodder API v2 compatible endpoints at /api/2/:
  - Auth: login/logout via HTTP Basic Auth or session
  - Devices: list and register sync devices
  - Subscriptions: get/add/remove per device, delta sync with ?since=
  - Episode actions: upload play/position events, syncs to EpisodeProgress
- Server URL for AntennaPod: https://diora.creamfresh.xyz/api/2/
- Bump SW cache diora-v4 → v5 to force re-fetch of updated app.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 06:36:41 +01:00
marwin
2fad4a726c Fix Books tab: auto-generate encryption key, remove password prompt
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 16s
- getOrCreateEncKey() now generates a random AES-GCM-256 key if none
  found in localStorage, instead of throwing an error
- Removed enc-key-prompt div from player.html entirely
- Simplified initBookDropZone() — removed prompt show/hide logic
- book-upload-area always visible, no longer hidden behind prompt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 22:16:22 +01:00
marwin
500b3fa780 Fix SW: only cache static assets, not API/HTML responses
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Caching /books/ caused stale empty list after upload. Caching / caused
stale window.USER_ID after session changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 22:05:50 +01:00
marwin
5ce9cec581 Show enc-key-prompt by default, hide only when key exists via JS
All checks were successful
Build and push Docker image / build (push) Successful in 11s
Test / test (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:57:41 +01:00
marwin
b234f74115 Bump SW cache to v3 to invalidate stale cached app.js and HTML
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:42:40 +01:00
marwin
e1b18f392e Show build time in bottom-right corner
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:35:41 +01:00
marwin
b9c5f835f4 Add password prompt in Books tab to derive encryption key on-device
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Bypasses unreliable login-form interception; user enters password once
per device to derive the same PBKDF2 key cross-device.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:29:51 +01:00
marwin
bbd920d75e Revert random key fallback, rely on PBKDF2 login-derived key
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-03-19 21:16:54 +01:00
marwin
2321b80127 Auto-generate encryption key if none exists instead of throwing
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:14:16 +01:00
marwin
31578db1bc Fix window.USER_ID not being set (const doesn't create window property)
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-19 21:04:51 +01:00