-
v4.5.5
StableAll checks were successfulRelease / Test backend (push) Successful in 5m47sRelease / Test UI (push) Successful in 1m4sRelease / Build and push images (push) Successful in 6m20sRelease / Deploy to prod (push) Successful in 3m53sRelease / Deploy to homelab (push) Successful in 8sRelease / Gitea Release (push) Successful in 25sreleased this
2026-04-27 11:46:23 +05:00 | -569 commits to main since this releaseDownloads
-
v4.5.3
StableSome checks failedRelease / Test UI (push) Has been cancelledRelease / Build and push images (push) Has been cancelledRelease / Test backend (push) Has been cancelledRelease / Deploy to prod (push) Has been cancelledRelease / Deploy to homelab (push) Has been cancelledRelease / Gitea Release (push) Has been cancelledreleased this
2026-04-24 22:47:52 +05:00 | -568 commits to main since this releaseSplit the single combined UpdateAIJob call at the end of each async
goroutine into two sequential calls (status first, payload second) so
that a failure writing the large results payload does not silently
prevent the job from being marked done. Added recover() to each
goroutine to catch and log panics. Affects chapter-names, description,
and image-gen handlers.Downloads
-
v4.5.2
StableAll checks were successfulRelease / Test backend (push) Successful in 6m5sRelease / Test UI (push) Successful in 1m44sRelease / Build and push images (push) Successful in 7m6sRelease / Deploy to prod (push) Successful in 3m47sRelease / Deploy to homelab (push) Successful in 8sRelease / Gitea Release (push) Successful in 44sreleased this
2026-04-24 18:24:25 +05:00 | -567 commits to main since this releaseLlama 4 Scout returns the model output directly as a JSON array in the
'response' field rather than as a plain string or [{"generated_text":"..."}].
The old fallback parsed it as [{"generated_text":""}] (Go JSON ignores
unknown fields) and silently returned an empty string — causing chapter-names
jobs to finish with results:null in the payload despite items_done matching
items_total.Fix: only accept the generated_text fallback when the value is non-empty;
otherwise return the raw JSON bytes as a string so callers (parseChapterTitlesJSON
etc.) can extract what they need.Downloads
-
v4.5.1
StableAll checks were successfulRelease / Test backend (push) Successful in 6m35sRelease / Test UI (push) Successful in 1m41sRelease / Build and push images (push) Successful in 4m39sRelease / Deploy to prod (push) Successful in 2m20sRelease / Deploy to homelab (push) Successful in 13sRelease / Gitea Release (push) Successful in 27sreleased this
2026-04-20 12:09:39 +05:00 | -566 commits to main since this releaseDownloads
-
v4.5.0
StableAll checks were successfulRelease / Test backend (push) Successful in 6m16sRelease / Test UI (push) Successful in 1m49sRelease / Build and push images (push) Successful in 7m41sRelease / Deploy to prod (push) Successful in 1m45sRelease / Deploy to homelab (push) Successful in 15sRelease / Gitea Release (push) Successful in 43sreleased this
2026-04-19 21:44:38 +05:00 | -565 commits to main since this releaseAdmins can now generate TTS audiobooks chapter-by-chapter and publish
them as standard RSS 2.0 + iTunes podcast feeds that Spotify, Apple
Podcasts, and any podcast app can subscribe to.Backend:
- POST /api/admin/podcast — creates ai_job (kind=podcast), spawns
goroutine that generates TTS for missing chapters and writes to MinIO - GET /podcast/{slug}.xml?voice= — public RSS feed with correct
pubDate (from chapters_idx.created) and enclosure length (MinIO stat) - GET /podcast/audio/{slug}/{n}/{voice} — public audio proxy, 302 to
presigned MinIO URL (no auth required for podcast clients) - GET /api/admin/podcast/{slug} — list podcast jobs for a book
- Add AudioObjectSize to AudioStore interface backed by MinIO StatObject
- Populate ChapterInfo.Date from chapters_idx.created in ListChapters
UI:
- New /admin/podcast page: book + voice selector, chapter range, live
progress bars, copy-feed-URL button, cancel button, how-to instructions - /api/admin/podcast SvelteKit proxy (injects admin Bearer token)
- Podcast link added to admin sidebar
Cleanup:
- Delete stray playwright screenshot files from repo root
- Add .playwright-mcp/ to .gitignore
Downloads
- POST /api/admin/podcast — creates ai_job (kind=podcast), spawns
-
v4.4.4
StableAll checks were successfulRelease / Test backend (push) Successful in 59sRelease / Test UI (push) Successful in 1m39sRelease / Build and push images (push) Successful in 8m9sRelease / Deploy to homelab (push) Successful in 23sRelease / Gitea Release (push) Successful in 1m37sRelease / Deploy to prod (push) Successful in 2m12sreleased this
2026-04-17 22:53:41 +05:00 | -563 commits to main since this release- Homepage hero: wider cover (w-32→w-36), adjusted info panel height,
hide genre pills on mobile (they wrap and waste vertical space) - Chapter reader: tighten top nav gap mb-8→mb-4 and heading gap
mb-6→mb-4 on mobile so content starts earlier - Library cards: hide genre tags on mobile (hidden sm:flex) — redundant
in a library context and cramped at 2-column density - Book detail: reduce hero bottom margin mb-8→mb-5 on mobile
- Catalogue list view: fix hardcoded hover:border-zinc-500 → brand
color, matching the grid view hover style
Downloads
- Homepage hero: wider cover (w-32→w-36), adjusted info panel height,
-
v4.4.3
StableSome checks failedRelease / Test backend (push) Successful in 56sRelease / Test UI (push) Successful in 1m48sRelease / Build and push images (push) Successful in 8m22sRelease / Deploy to homelab (push) Successful in 22sRelease / Deploy to prod (push) Failing after 1m1sRelease / Gitea Release (push) Successful in 2m3sreleased this
2026-04-17 22:28:02 +05:00 | -562 commits to main since this release- Discover loading skeleton: add borders and book icon placeholder so
card shapes are visible on all dark themes (was invisible on forest) - Library grid cards: match catalogue hover style (brand border, surface
lift, shadow, -translate-y-0.5) and remove hardcoded zinc-500 border - Reading progress bar: increase height 2px→3px and add brand glow shadow
Downloads
- Discover loading skeleton: add borders and book icon placeholder so
-
v4.4.2
StableAll checks were successfulRelease / Test UI (push) Successful in 57sRelease / Test backend (push) Successful in 6m10sRelease / Build and push images (push) Successful in 4m33sRelease / Deploy to homelab (push) Successful in 17sRelease / Gitea Release (push) Successful in 26sRelease / Deploy to prod (push) Successful in 2m35sreleased this
2026-04-17 17:00:42 +05:00 | -561 commits to main since this releaseBook detail: stronger blurred cover bg (opacity 0.35 + saturate), larger
cover (sm:w-56), more dramatic gradient, bigger title (sm:text-4xl).
Homepage hero: atmospheric blurred cover bg matching current carousel book.
Catalogue: cards now lift on hover with brand border + shadow.Downloads
-
v4.3.7
StableAll checks were successfulRelease / Test backend (push) Successful in 1m3sRelease / Test UI (push) Successful in 1m50sRelease / Build and push images (push) Successful in 7m32sRelease / Deploy to homelab (push) Successful in 16sRelease / Gitea Release (push) Successful in 27sRelease / Deploy to prod (push) Successful in 2m21sreleased this
2026-04-17 15:57:54 +05:00 | -559 commits to main since this releaseIssue: Two sequential 'docker compose up' commands caused race condition:
- First command (--no-deps) starts removing containers
- Second command (--remove-orphans) tries to remove same containers
- Result: 'removal of container is already in progress' error
Fix: Combine into single command with both flags:
docker compose up -d --no-deps --remove-orphansThis ensures atomic operation without race conditions.
Downloads
-
v4.4.1
StableSome checks failedRelease / Test backend (push) Successful in 1m3sRelease / Test UI (push) Successful in 58sRelease / Build and push images (push) Successful in 5m55sRelease / Deploy to prod (push) Failing after 48sRelease / Deploy to homelab (push) Successful in 21sRelease / Gitea Release (push) Successful in 29sreleased this
2026-04-17 13:32:48 +05:00 | -557 commits to main since this release- Catalogue/cover: rewrite raw scraped cover URLs to /api/cover/{domain}/{slug}
in handleCatalogue so all covers route through the backend proxy; fix broken
cdn.novelfire.net fallback in handleGetCover to read stored URL from PocketBase - Catalogue/profile: add Svelte 5 onerror handlers on cover
tags to show
letter-initial placeholder when image fails to load - Library page: read ?status URL param to initialise activeShelf tab on load so
/books?status=reading correctly pre-selects the Reading tab - Sessions: filter bot/tool user-agents (curl, python, wget, etc.) and debug-IP
sessions from listUserSessions display; also purge them in pruneStaleUserSessions - Profile: show email under username, quick stats chips (streak/chapters/completed)
in header, reading count on Library row, dedicated Sign out row, history covers
routed through /api/cover proxy
Downloads
- Catalogue/cover: rewrite raw scraped cover URLs to /api/cover/{domain}/{slug}