Commit Graph

406 Commits

Author SHA1 Message Date
Admin
278e292956 fix(home): use book.summary instead of book.description in hero card
Some checks failed
CI / Backend (push) Successful in 1m3s
CI / UI (push) Successful in 40s
Release / Docker / caddy (push) Failing after 10s
Release / Test backend (push) Successful in 40s
CI / UI (pull_request) Successful in 41s
CI / Backend (pull_request) Successful in 59s
Release / Docker / runner (push) Failing after 38s
Release / Docker / backend (push) Successful in 3m35s
Release / Check ui (push) Successful in 1m1s
Release / Docker / ui (push) Successful in 2m50s
Release / Gitea Release (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.9
2026-03-30 19:44:25 +05:00
Admin
76de5eb491 feat(reader): chapter comments + readers-this-week count
Some checks failed
CI / Backend (push) Successful in 48s
CI / UI (push) Failing after 22s
Release / Check ui (push) Failing after 33s
Release / Docker / ui (push) Has been skipped
Release / Test backend (push) Successful in 53s
Release / Docker / caddy (push) Successful in 48s
CI / Backend (pull_request) Successful in 44s
CI / UI (pull_request) Failing after 44s
Release / Docker / runner (push) Failing after 46s
Release / Docker / backend (push) Successful in 1m54s
Release / Gitea Release (push) Has been skipped
- CommentsSection now accepts a chapter prop and scopes comments to that chapter
- Chapter reader page mounts CommentsSection with current chapter number
- Book detail page shows rolling 7-day unique reader count badge
- API GET/POST pass chapter param; pocketbase listComments filters by chapter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.8
2026-03-30 19:34:12 +05:00
Admin
c6597c8d19 feat(home): hero resume card, horizontal scroll rows, genre strip, dedup
Some checks failed
CI / Backend (push) Successful in 1m0s
CI / UI (push) Failing after 26s
Release / Test backend (push) Successful in 53s
CI / Backend (pull_request) Successful in 45s
Release / Docker / caddy (push) Successful in 1m13s
CI / UI (pull_request) Failing after 33s
Release / Docker / runner (push) Failing after 1m27s
Release / Docker / backend (push) Successful in 3m35s
Release / Check ui (push) Failing after 31s
Release / Docker / ui (push) Has been skipped
Release / Gitea Release (push) Has been skipped
- First continue-reading book becomes a wide hero card with title,
  description, genre tags, and a prominent Resume ch.N CTA
- Remaining in-progress books move to a horizontal scroll shelf
- Recently Updated deduplicates by slug; books with multiple new
  chapters show a green "+N ch." badge
- Genre discovery strip (horizontal scroll) links to /catalogue?genre=X
- Stats demoted to a subtle two-number footer bar
- All rows use horizontal scroll instead of fixed grids

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.7
2026-03-30 19:20:28 +05:00
Admin
e8d7108753 feat(themes): add light, light-slate, and light-rose themes
Some checks failed
CI / Backend (push) Successful in 30s
Release / Test backend (push) Failing after 11s
Release / Docker / backend (push) Has been skipped
Release / Docker / runner (push) Has been skipped
CI / UI (push) Successful in 35s
Release / Docker / caddy (push) Successful in 58s
Release / Check ui (push) Successful in 1m7s
CI / Backend (pull_request) Successful in 31s
CI / UI (pull_request) Successful in 1m1s
Release / Docker / ui (push) Failing after 2m43s
Release / Gitea Release (push) Has been skipped
Three light variants mirroring the existing dark set. All use CSS custom
properties so no component changes are needed. Theme dots in the header
and mobile drawer show a separator between dark/light groups; light-theme
swatches get a subtle ring so they're visible on light backgrounds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.6
2026-03-30 19:13:25 +05:00
Admin
90dbecfa17 feat(profile): auto-save settings, merge sections, fix font/size preview
Some checks failed
CI / Backend (push) Successful in 30s
Release / Test backend (push) Successful in 33s
Release / Docker / caddy (push) Failing after 10s
CI / UI (push) Successful in 52s
Release / Check ui (push) Successful in 1m7s
CI / Backend (pull_request) Successful in 40s
CI / UI (pull_request) Successful in 53s
Release / Docker / runner (push) Failing after 46s
Release / Docker / backend (push) Successful in 3m16s
Release / Docker / ui (push) Successful in 5m2s
Release / Gitea Release (push) Has been skipped
- Remove both "Save settings" buttons; all settings now auto-save with
  800ms debounce and show a transient "✓ Saved" indicator
- Apply theme, font family, and font size to context immediately on
  change so the preview is live without waiting for the save
- Merge Appearance + Reading settings into a single Preferences card
  with dividers — fewer sections, less visual noise
- Pro users see a compact subscription row; free users see upgrade CTAs
- Speed label splits value and units (shows "1.5x" separately in brand
  color) for cleaner readout
- Auto-advance toggle gains a subtitle description

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.5
2026-03-30 19:07:51 +05:00
Admin
2deb306419 fix(i18n+settings): rename pt-BR→pt, fix theme/locale persistence
Some checks failed
CI / Backend (push) Successful in 56s
CI / UI (push) Successful in 38s
Release / Test backend (push) Successful in 42s
Release / Docker / caddy (push) Failing after 11s
CI / Backend (pull_request) Failing after 11s
Release / Docker / backend (push) Failing after 38s
CI / UI (pull_request) Successful in 44s
Release / Check ui (push) Successful in 1m53s
Release / Docker / runner (push) Failing after 1m26s
Release / Docker / ui (push) Successful in 3m46s
Release / Gitea Release (push) Has been skipped
Root cause: user_settings table was missing theme, locale, font_family,
font_size columns — PocketBase silently dropped them on every save.
Added the four columns via PocketBase API.

Also:
- listOne now sorts by -updated so the most-recent settings record wins
- PARAGLIDE_LOCALE cookie is now cleared when switching back to English
- pt-BR renamed to pt throughout (messages, inlang settings, validLocales)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.4
2026-03-30 19:05:14 +05:00
Admin
fd283bf6c6 fix(sessions): prune stale sessions on login to prevent accumulation
Some checks failed
CI / Backend (push) Successful in 43s
CI / UI (push) Successful in 36s
Release / Test backend (push) Successful in 56s
Release / Check ui (push) Successful in 50s
Release / Docker / caddy (push) Successful in 40s
CI / UI (pull_request) Failing after 37s
CI / Backend (pull_request) Successful in 48s
Release / Docker / runner (push) Failing after 32s
Release / Docker / backend (push) Successful in 2m39s
Release / Docker / ui (push) Successful in 1m45s
Release / Gitea Release (push) Has been skipped
Sessions not seen in 30+ days are deleted in the background each time
a new session is created. No cron job needed — self-cleaning on login.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.3
2026-03-30 18:24:16 +05:00
Admin
3154a22500 fix(errors): redesign all Caddy error pages with consistent branded layout
Some checks failed
CI / UI (push) Successful in 43s
Release / Test backend (push) Successful in 45s
CI / Backend (push) Successful in 48s
Release / Check ui (push) Successful in 36s
CI / Backend (pull_request) Successful in 47s
CI / UI (pull_request) Successful in 36s
Release / Docker / caddy (push) Failing after 1m50s
Release / Docker / runner (push) Successful in 1m57s
Release / Docker / backend (push) Successful in 3m13s
Release / Docker / ui (push) Successful in 2m42s
Release / Gitea Release (push) Has been skipped
Add header/footer, LibNovel wordmark, pulsing status indicator, faint
watermark code, and auto-refresh countdown (20s for 502/504, 30s for 503).
Fix two-tone background by setting background on html+body. 404 is static
with no auto-refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.2
2026-03-30 18:22:14 +05:00
Admin
61e0d98057 feat(ui): declutter header — user menu + lang dropdown, mobile theme/lang
Some checks failed
CI / Backend (pull_request) Successful in 55s
CI / UI (pull_request) Successful in 49s
CI / UI (push) Failing after 35s
Release / Test backend (push) Successful in 42s
CI / Backend (push) Successful in 57s
Release / Check ui (push) Successful in 36s
Release / Docker / caddy (push) Successful in 1m11s
Release / Docker / runner (push) Successful in 2m5s
Release / Docker / ui (push) Successful in 2m2s
Release / Docker / backend (push) Failing after 2m32s
Release / Gitea Release (push) Has been skipped
Desktop header before: logo · Library · Catalogue · Feedback · ●●● · EN RU ID PT-BR FR · Admin · username · Sign out
Desktop header after:  logo · Library · Catalogue · Feedback · ●●● · [🌐 EN ▾] · [avatar ▾]

Changes:
- Theme dots kept but made slightly smaller (3.5 → 3.5, less gap)
- 5 bare language codes replaced with a compact globe + current locale
  dropdown (click to expand all 5 options)
- Admin link, username, and Sign out collapsed into a single user-initial
  avatar dropdown (Profile / Admin panel / Sign out)
- Click-outside overlay closes any open dropdown
- Mobile drawer: added Theme and Language rows so users can switch both
  without opening the desktop header
- Footer locale switcher removed (redundant with header and mobile drawer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.1
2026-03-30 14:54:46 +05:00
Admin
601c26d436 fix(ui): theme token consistency, seek bar a11y, colour polish
All checks were successful
CI / Backend (push) Successful in 36s
CI / Backend (pull_request) Successful in 46s
CI / UI (push) Successful in 59s
CI / UI (pull_request) Successful in 37s
- Add --color-success variable to all three themes
- Replace hard-coded amber/green Tailwind colours with CSS variables:
    Pro badge + discount badge: bg-amber-400/15 → bg-(--color-brand)/15
    Saved confirmation:         text-green-400 → text-(--color-success)
    Catalogue flash messages:   emerald/yellow → success/brand tokens
    Login hover border:         border-zinc-600 → border-(--color-brand)/50
- Seek bar in mini-player now has aria-label (player_seek_label)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 14:24:34 +05:00
Admin
4a267d8fd8 feat: open catalogue + book pages to public (hybrid open model)
All checks were successful
CI / Backend (pull_request) Successful in 47s
CI / UI (pull_request) Successful in 44s
CI / Backend (push) Successful in 44s
Release / Test backend (push) Successful in 28s
CI / UI (push) Successful in 1m12s
Release / Check ui (push) Successful in 56s
Release / Docker / caddy (push) Successful in 1m9s
Release / Docker / ui (push) Successful in 1m57s
Release / Docker / runner (push) Successful in 3m45s
Release / Docker / backend (push) Successful in 3m50s
Release / Gitea Release (push) Successful in 14s
Reading content is now publicly accessible without login:
- /catalogue, /books/[slug], /books/[slug]/chapters, /books/[slug]/chapters/[n]
  are all public — no login redirect
- /books (personal library), /profile, /admin remain protected

Unauthenticated UX:
- Chapter page: "Audio narration available — Sign in to listen" banner
  replaces the audio player for logged-out visitors
- Book detail: bookmark icon links to /login instead of triggering
  the save action (both desktop and mobile CTAs)

SEO:
- robots.txt updated: Allow /books/ and /catalogue, Disallow /books (library)
- sitemap.xml now includes /catalogue as primary crawl entry point

i18n: added reader_signin_for_audio, reader_signin_audio_desc,
      book_detail_signin_to_save in all 5 languages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.5.0
2026-03-30 14:16:22 +05:00
Admin
c9478a67fb fix(ci): use full gitea.com URL for gitea-release-action
All checks were successful
CI / UI (push) Successful in 41s
CI / Backend (push) Successful in 50s
Release / Test backend (push) Successful in 56s
Release / Check ui (push) Successful in 34s
CI / Backend (pull_request) Successful in 46s
CI / UI (pull_request) Successful in 34s
Release / Docker / runner (push) Successful in 3m15s
Release / Docker / backend (push) Successful in 3m29s
Release / Docker / ui (push) Successful in 2m30s
Release / Docker / caddy (push) Successful in 1m17s
Release / Gitea Release (push) Successful in 17s
Bare `actions/` references resolve to github.com by default in act_runner.
gitea-release-action lives on gitea.com so must use the full https:// URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.4.1
2026-03-29 22:38:36 +05:00
Admin
1b4835daeb fix(homelab): switch Fider SMTP to port 587 + STARTTLS
All checks were successful
CI / Backend (pull_request) Successful in 50s
CI / UI (pull_request) Successful in 1m10s
Port 465 (SMTPS) is blocked on the homelab server. Port 587 with STARTTLS
works. Updated FIDER_SMTP_PORT=587 and FIDER_SMTP_ENABLE_STARTTLS=true in
Doppler prd_homelab, and made EMAIL_SMTP_ENABLE_STARTTLS dynamic so it reads
from Doppler instead of being hardcoded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 22:16:01 +05:00
Admin
c9c12fc4a8 fix(infra): correct doppler entrypoint for watchtower container
All checks were successful
CI / UI (pull_request) Successful in 39s
CI / Backend (pull_request) Successful in 45s
- Fix binary path: /usr/bin/doppler (not /usr/local/bin)
- Mount /root/.doppler config so the container can auth without DOPPLER_TOKEN env
- Set HOME=/root so doppler locates the mounted config directory
- Add explicit --project/--config flags to override directory-scope lookup
- Production: --project libnovel --config prd
- Homelab: --project libnovel --config prd_homelab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 22:05:33 +05:00
Admin
dd35024d02 chore(infra): run watchtower via doppler for fresh secrets on restart
All checks were successful
CI / UI (pull_request) Successful in 39s
CI / Backend (pull_request) Successful in 47s
Mount the host doppler binary into the watchtower container and use it as
the entrypoint so WATCHTOWER_NOTIFICATION_URL and other secrets are fetched
from Doppler each time the container starts, rather than being baked in at
compose-up time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 21:52:32 +05:00
Admin
4b8104f087 feat(ui): language persistence, theme fix, font/size settings, header quick-access
Some checks failed
CI / UI (push) Failing after 54s
CI / Backend (push) Successful in 1m56s
Release / Test backend (push) Successful in 41s
Release / Check ui (push) Successful in 50s
Release / Docker / caddy (push) Successful in 54s
CI / Backend (pull_request) Successful in 45s
CI / UI (pull_request) Successful in 50s
Release / Docker / ui (push) Successful in 2m23s
Release / Docker / runner (push) Successful in 3m15s
Release / Docker / backend (push) Successful in 2m3s
Release / Gitea Release (push) Failing after 2s
- Fix language not persisting after refresh: save locale in user_settings,
  set PARAGLIDE_LOCALE cookie from DB preference on server load
- Fix theme change not applying: context setter was mismatched (setTheme vs current)
- Add font family (system/serif/mono) and text size (sm/md/lg/xl) user settings
  stored in DB and applied via CSS custom properties
- Add theme color dots and language picker to desktop header for quick access
- Footer locale switcher now saves preference to DB before switching
- Remove change password section (OAuth-only, no password login)
- Fix active sessions piling up: reuse existing session on re-login via OAuth
- Extend speed step cycle to include 2.5× and 3.0× (matching profile slider)
- Replace plain checkbox with modern toggle switch for auto-next setting
- Fix catalogue status labels (ongoing/completed) to use translation keys
- Add font family and text size translation keys to all 5 locale files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.4.0
2026-03-29 21:43:00 +05:00
Admin
5da880d189 fix(runner): add heartbeat + translation polling to asynq mode
All checks were successful
CI / UI (push) Successful in 57s
CI / Backend (pull_request) Successful in 1m4s
CI / Backend (push) Successful in 1m45s
CI / UI (pull_request) Successful in 51s
Two bugs prevented asynq mode from working correctly on the homelab runner:

1. No healthcheck file: asynq mode never writes /tmp/runner.alive, so
   Docker healthcheck always fails. Added heartbeat goroutine that
   writes the file every StaleTaskThreshold (30s).

2. Translation tasks not dispatched: translation uses ClaimNextTranslationTask
   (PocketBase poll queue), not Redis/asynq. Audio + scrape use asynq mux,
   but translation sits in PocketBase forever. Added pollTranslationTasks()
   goroutine that polls PocketBase on the same PollInterval as the old
   poll() loop.

All Go tests pass (go test ./... in backend/).
2026-03-29 20:22:37 +05:00
Admin
98631df47a feat(billing): Polar.sh Pro subscription integration
Some checks failed
CI / UI (push) Successful in 1m36s
CI / Backend (push) Successful in 59s
Release / Test backend (push) Successful in 39s
Release / Check ui (push) Successful in 33s
CI / Backend (pull_request) Successful in 44s
CI / UI (pull_request) Successful in 34s
Release / Docker / runner (push) Successful in 2m44s
Release / Docker / ui (push) Successful in 2m45s
Release / Docker / backend (push) Successful in 3m35s
Release / Docker / caddy (push) Successful in 1m8s
Release / Gitea Release (push) Failing after 2s
- Webhook handler verifies HMAC-SHA256 sig and updates user role on
  subscription.created / subscription.updated / subscription.revoked
- Audio endpoint gated: free users limited to 3 chapters/day via Valkey
  counter; returns 402 {error:'pro_required'} when limit reached
- Translation proxy endpoint enforces 402 for non-pro users
- AudioPlayer.svelte surfaces 402 via onProRequired callback + upgrade banner
- Chapter page shows lock icon + upgrade prompts for gated translation langs
- Profile page: subscription section shows Pro badge + manage link (active)
  or monthly/annual checkout buttons (free); isPro resolved fresh from DB
- i18n: 13 new profile_subscription_* keys across all 5 locales
v2.3.25
2026-03-29 13:21:23 +05:00
Admin
83b3dccc41 fix(ui): run paraglide compile in prepare so CI type-check finds $lib/paraglide/server
Some checks failed
CI / Backend (pull_request) Successful in 50s
CI / UI (pull_request) Successful in 1m0s
CI / UI (push) Successful in 42s
Release / Test backend (push) Successful in 46s
CI / Backend (push) Successful in 1m1s
Release / Check ui (push) Successful in 34s
Release / Docker / caddy (push) Successful in 1m4s
Release / Docker / runner (push) Successful in 2m7s
Release / Docker / ui (push) Successful in 2m26s
Release / Docker / backend (push) Successful in 3m28s
Release / Gitea Release (push) Failing after 2s
The paraglide output dir has its own .gitignore (ignores everything), so
generated files are never committed. CI ran `npm ci` then `svelte-check`
without ever invoking vite, so $lib/paraglide/server was missing at
type-check time.

Adding `paraglide-js compile` to the prepare script ensures the output is
regenerated during `npm ci` before svelte-kit sync and svelte-check run.

Also adds translation_jobs collection to pb-init-v3.sh.
v2.3.24
2026-03-29 11:50:06 +05:00
Admin
588e455aae chore(homelab): add LibreTranslate service to runner compose
Some checks failed
CI / Backend (pull_request) Failing after 11s
CI / UI (pull_request) Failing after 11s
- libretranslate/libretranslate:latest, internal Docker network only
- LT_LOAD_ONLY=en,ru,id,pt,fr (only pairs the runner needs)
- LT_API_KEYS=true, key stored in Doppler prd_homelab
- Runner depends_on libretranslate (service_healthy)
- LIBRETRANSLATE_URL=http://libretranslate:5000 (no tunnel needed)
- RUNNER_MAX_CONCURRENT_TRANSLATION wired from Doppler
2026-03-29 11:42:52 +05:00
Admin
28ac8d8826 feat(translation): machine translation pipeline + admin bulk enqueue UI
Some checks failed
CI / Backend (push) Failing after 11s
Release / Check ui (push) Failing after 51s
Release / Docker / ui (push) Has been skipped
CI / UI (push) Failing after 55s
Release / Test backend (push) Failing after 1m9s
Release / Docker / backend (push) Has been skipped
Release / Docker / runner (push) Has been skipped
Release / Docker / caddy (push) Failing after 28s
Release / Gitea Release (push) Has been skipped
CI / UI (pull_request) Failing after 42s
CI / Backend (pull_request) Successful in 3m45s
- LibreTranslate client (chunks on blank lines, ≤4500 chars, 3-goroutine semaphore)
- Runner translation task loop (OTel, heartbeat, MinIO storage)
- PocketBase translation_jobs collection support (create/claim/finish/list)
- Per-chapter language switcher on chapter reader (EN/RU/ID/PT/FR, polls until done)
- Admin /admin/translation page: bulk enqueue form + live-polling jobs table
- New backend routes: POST /api/translation/{slug}/{n}, GET /api/translation/status,
  GET /api/translation/{slug}/{n}, GET /api/admin/translation/jobs,
  POST /api/admin/translation/bulk
- ListTranslationTasks added to taskqueue.Reader interface + store impl
- All builds and tests pass; svelte-check: 0 errors
v2.3.23
2026-03-29 11:32:42 +05:00
Admin
0a3a61a3ef feat(i18n): add Paraglide i18n with 5 locales (v2.3.22)
Some checks failed
CI / Backend (pull_request) Successful in 41s
CI / UI (pull_request) Failing after 27s
CI / UI (push) Failing after 27s
CI / Backend (push) Successful in 48s
Release / Test backend (push) Successful in 23s
Release / Check ui (push) Failing after 33s
Release / Docker / ui (push) Has been skipped
Release / Docker / caddy (push) Failing after 52s
Release / Docker / backend (push) Failing after 11s
Release / Docker / runner (push) Successful in 1m51s
Release / Gitea Release (push) Has been skipped
- Install @inlang/paraglide-js v2.15.1; configure project.inlang settings
- Add en/ru/id/pt-BR/fr message catalogues (~140 keys each)
- Wire paraglideVitePlugin in vite.config.ts, reroute hook in hooks.ts,
  and paraglideHandle middleware in hooks.server.ts
- Migrate all routes and shared components to use m.*() message calls
- Fix duplicate onMount body in chapters/[n]/+page.svelte
- Build passes; svelte-check: 0 errors, 3 pre-existing warnings
v2.3.22
2026-03-29 10:43:53 +05:00
Admin
7a2a4fc755 feat(ui): theme system — amber/slate/rose, profile picker, full token migration
Some checks failed
CI / Backend (pull_request) Successful in 44s
CI / UI (pull_request) Successful in 25s
CI / UI (push) Successful in 27s
Release / Test backend (push) Successful in 42s
CI / Backend (push) Successful in 44s
Release / Check ui (push) Successful in 24s
Release / Docker / caddy (push) Failing after 1m4s
Release / Docker / backend (push) Failing after 44s
Release / Docker / ui (push) Failing after 29s
Release / Docker / runner (push) Failing after 54s
Release / Gitea Release (push) Has been skipped
- Add CSS custom property token system in app.css (@theme + [data-theme] overrides)
- Three themes: amber (default), slate (indigo/dark), rose (dark pink)
- Flash prevention via inline <script> in <svelte:head> sets data-theme before paint
- Theme context (setContext/getContext) in +layout.svelte for live preview
- Theme persisted via PocketBase user_settings (PBUserSettings.theme field)
- /api/settings GET/PUT updated to handle theme field alongside existing settings
- Profile page: new Appearance section with 3 colour-swatch theme picker
- Full token migration across all 36 route/component files:
  zinc/amber hardcoded Tailwind classes → CSS var utilities (bg-(--color-surface), etc.)
- UI primitives (Badge, Button, Card, Dialog, Separator, Textarea) migrated
- accent-amber-400 replaced with inline style accent-color: var(--color-brand)
v2.3.21
2026-03-28 23:57:16 +05:00
Admin
801928aadf fix(scraper): update status and genres selectors for current novelfire.net HTML
Some checks failed
CI / Backend (push) Failing after 11s
CI / UI (push) Successful in 48s
Release / Test backend (push) Successful in 50s
Release / Check ui (push) Successful in 55s
CI / UI (pull_request) Successful in 37s
Release / Docker / caddy (push) Successful in 47s
CI / Backend (pull_request) Successful in 46s
Release / Docker / runner (push) Successful in 2m37s
Release / Docker / ui (push) Successful in 2m42s
Release / Docker / backend (push) Successful in 3m13s
Release / Gitea Release (push) Failing after 2s
novelfire.net changed its book page structure. Old selectors produced empty
status and null genres for every book, causing all Meilisearch filters to
return zero results.

Old → new:
- status:  <span class="status">  →  <strong class="ongoing|completed|hiatus">
  (text lowercased for consistent index values)
- genres:  <div class="genres"> <a>  →  <div class="categories"> <a class="property-item">
  (text lowercased for consistent index values)

Adds TestParseMetadataSelectors to guard against future regressions.
v2.3.20
2026-03-28 22:54:35 +05:00
Admin
040072c3f5 docs(d2): update architecture and api-routing diagrams to current state
All checks were successful
CI / Backend (pull_request) Successful in 33s
CI / UI (pull_request) Successful in 40s
architecture.d2:
- Split app into prod VPS (165.22.70.138) and homelab runner (192.168.0.109)
- Add CrowdSec, Dozzle agent, pocket-tts (voice samples)
- Valkey now shown as Asynq job queue in addition to presign cache
- Add caddy-l4 Redis TCP proxy (:6380) to Caddy label
- Add CI/CD node (Gitea Actions) with full job list incl. releases.json bake
- Remove runner from prod app group (it runs on homelab only)
- Watchtower: note runner is label-disabled on prod

api-routing.d2:
- Add /api/presign/* routes to backend (presign_be group)
- Add /api/audio POST + status GET to both sk and be
- Add /api/scrape/book and /api/scrape/book/range to scrape_sk
- Catalogue: annotate Meilisearch vs legacy browse
- Add Meilisearch filter/sort fields to storage node
- Add Asynq queue note to Valkey storage node
- Fix presign proxy: sk routes through be.presign_be, not directly to storage
2026-03-28 22:44:31 +05:00
Admin
6a76e97a67 fix(ci): follow HTTP redirect and validate JSON in fetch-releases step
Some checks failed
CI / Backend (push) Successful in 26s
Release / Test backend (push) Successful in 42s
Release / Check ui (push) Successful in 28s
CI / UI (push) Successful in 1m4s
CI / UI (pull_request) Failing after 11s
CI / Backend (pull_request) Successful in 27s
Release / Docker / caddy (push) Successful in 1m3s
Release / Docker / runner (push) Failing after 1m3s
Release / Docker / ui (push) Successful in 1m53s
Release / Docker / backend (push) Failing after 4m2s
Release / Gitea Release (push) Has been skipped
curl -sf without -L silently wrote '301 Moved Permanently' to releases.json
instead of following the http→https redirect. Added -L to follow redirects,
set -euo pipefail, and jq type validation so the step fails hard on bad JSON.
v2.3.19
2026-03-28 22:38:09 +05:00
Admin
71f79c8e02 feat(admin): bake changelog into UI image at CI build time
Some checks failed
CI / Backend (push) Failing after 11s
Release / Test backend (push) Successful in 34s
CI / UI (push) Successful in 48s
Release / Check ui (push) Successful in 1m5s
Release / Docker / caddy (push) Successful in 52s
CI / Backend (pull_request) Successful in 42s
CI / UI (pull_request) Successful in 37s
Release / Docker / backend (push) Failing after 44s
Release / Docker / ui (push) Successful in 2m24s
Release / Docker / runner (push) Failing after 3m24s
Release / Gitea Release (push) Has been skipped
Replace runtime Gitea API fetch with fs.readFileSync of releases.json,
which CI writes to ui/static/ before the Docker build context is sent.
Eliminates prod→homelab network dependency for the changelog page.
v2.3.18
2026-03-28 21:49:52 +05:00
Admin
5ee4a06654 feat(admin): compact scrape page layout; add Changelog page
Some checks failed
CI / Backend (push) Successful in 48s
CI / UI (push) Successful in 35s
Release / Test backend (push) Successful in 39s
Release / Check ui (push) Successful in 36s
CI / Backend (pull_request) Successful in 41s
Release / Docker / caddy (push) Successful in 1m31s
CI / UI (pull_request) Successful in 49s
Release / Docker / backend (push) Failing after 1m9s
Release / Docker / ui (push) Successful in 2m18s
Release / Docker / runner (push) Successful in 3m49s
Release / Gitea Release (push) Has been skipped
- Scrape page: replace three large cards + genre card with a compact
  bordered table of rows (label + inline controls per action). Visually
  much lighter, all controls visible without scrolling.
- Admin sidebar: add Changelog link after Audio.
- New /admin/changelog page: fetches releases from Gitea API and renders
  them as a clean list (tag, title, date, body).
v2.3.17
2026-03-28 21:41:13 +05:00
Admin
63b286d0a4 fix(caddy): move layer4 into global block; use :6380 listener address
Some checks failed
CI / Backend (push) Successful in 30s
CI / UI (push) Successful in 39s
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 25s
CI / UI (pull_request) Successful in 25s
Release / Docker / caddy (push) Successful in 1m9s
CI / Backend (pull_request) Successful in 1m14s
Release / Docker / ui (push) Successful in 3m56s
Release / Docker / runner (push) Successful in 4m41s
Release / Docker / backend (push) Successful in 7m51s
Release / Gitea Release (push) Failing after 2s
The bare { } block at the bottom was a second global options block which
Caddy's caddyfile adapter rejects on reload. Merged layer4 into the single
top-level global block. Changed listener from hostname (redis.libnovel.cc:6380)
to :6380 so Caddy binds to the local interface rather than the Cloudflare IP
that resolves for the hostname.
v2.3.16
2026-03-28 21:36:12 +05:00
Admin
d3f06c5c40 fix(caddy): add 404 error page; add health checks and lb_try_duration to ui upstream
Some checks failed
Release / Test backend (push) Successful in 26s
CI / Backend (push) Successful in 42s
CI / UI (push) Successful in 47s
Release / Check ui (push) Successful in 26s
CI / UI (pull_request) Successful in 26s
CI / Backend (pull_request) Successful in 44s
Release / Docker / caddy (push) Successful in 53s
Release / Docker / backend (push) Failing after 1m4s
Release / Docker / runner (push) Failing after 1m3s
Release / Docker / ui (push) Successful in 1m54s
Release / Gitea Release (push) Has been skipped
- Add caddy/errors/404.html (matches existing 502/503/504 style)
- Add handle_errors 404 block in Caddyfile
- Add active health checks (5s interval) and lb_try_duration 3s to the
  ui reverse_proxy so Caddy detects Watchtower container replacements
  quickly and serves the 502 maintenance page instead of a raw error
v2.3.15
2026-03-28 21:32:04 +05:00
Admin
e71ddc2f8b fix(backend): add ffmpeg to backend image for pocket-tts voice sample generation
Some checks failed
CI / Backend (push) Successful in 29s
CI / UI (push) Successful in 27s
Release / Test backend (push) Successful in 37s
CI / Backend (pull_request) Failing after 11s
Release / Check ui (push) Successful in 49s
Release / Docker / caddy (push) Successful in 57s
CI / UI (pull_request) Successful in 56s
Release / Docker / runner (push) Failing after 1m22s
Release / Docker / backend (push) Failing after 1m46s
Release / Docker / ui (push) Successful in 2m25s
Release / Gitea Release (push) Has been skipped
handlePresignVoiceSample generates voice samples on demand via pocket-tts,
which requires WAV→MP3 transcoding via ffmpeg. The backend was using
distroless/static (no ffmpeg) so all pocket-tts preview requests returned 500.
Switch backend stage to Alpine + ffmpeg, matching the runner image.
v2.3.14
2026-03-28 21:24:59 +05:00
Admin
b783dae5f4 refactor(admin): replace tab bar with sidebar layout
Some checks failed
CI / Backend (push) Successful in 38s
CI / UI (push) Successful in 42s
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 33s
CI / Backend (pull_request) Successful in 28s
Release / Docker / caddy (push) Successful in 1m11s
CI / UI (pull_request) Successful in 29s
Release / Docker / ui (push) Successful in 1m54s
Release / Docker / runner (push) Successful in 4m27s
Release / Docker / backend (push) Failing after 5m11s
Release / Gitea Release (push) Has been skipped
Move admin navigation from a two-row tab strip into a persistent left
sidebar with grouped sections (Pages / Tools). Consolidate Scrape and
Audio entries in the global top nav into a single Admin link.
v2.3.13
2026-03-28 21:15:49 +05:00
Admin
dcf40197d4 fix(ui): brighten footer link text for readability on dark background
Some checks failed
CI / Backend (push) Successful in 51s
CI / UI (push) Successful in 28s
Release / Test backend (push) Successful in 50s
Release / Docker / caddy (push) Successful in 1m0s
Release / Check ui (push) Successful in 1m15s
CI / Backend (pull_request) Successful in 41s
CI / UI (pull_request) Successful in 32s
Release / Docker / ui (push) Successful in 2m2s
Release / Docker / backend (push) Successful in 4m9s
Release / Docker / runner (push) Successful in 5m46s
Release / Gitea Release (push) Failing after 1s
v2.3.12
2026-03-28 21:12:46 +05:00
Admin
9dae5e7cc0 fix(infra): add POCKET_TTS_URL to backend and runner services
Some checks failed
CI / Backend (push) Successful in 27s
Release / Test backend (push) Successful in 39s
CI / UI (push) Successful in 48s
Release / Check ui (push) Successful in 25s
CI / UI (pull_request) Successful in 25s
CI / Backend (pull_request) Successful in 45s
Release / Docker / caddy (push) Successful in 1m7s
Release / Docker / backend (push) Successful in 2m17s
Release / Docker / ui (push) Successful in 2m9s
Release / Docker / runner (push) Failing after 3m34s
Release / Gitea Release (push) Has been skipped
Backend was missing POCKET_TTS_URL entirely — pocketTTSClient was nil
so voices() only returned 67 Kokoro voices. Runner already had the var
via Doppler but it was absent from the compose environment block.

Also fix stray leading space on backend environment: key (YAML parse error).

Verified: /api/voices now returns 87 voices (67 kokoro + 20 pocket-tts).
v2.3.11
2026-03-28 20:54:04 +05:00
Admin
908f5679fd fix(ui): defer catalogue filter navigation to explicit Apply button
Some checks failed
CI / Backend (push) Failing after 11s
Release / Check ui (push) Successful in 34s
Release / Test backend (push) Successful in 52s
CI / UI (push) Successful in 55s
Release / Docker / caddy (push) Successful in 48s
CI / UI (pull_request) Successful in 39s
CI / Backend (pull_request) Successful in 43s
Release / Docker / runner (push) Failing after 38s
Release / Docker / ui (push) Successful in 1m55s
Release / Docker / backend (push) Successful in 3m30s
Release / Gitea Release (push) Has been skipped
Removed onchange→navigateWithFilters from all three selects — the
immediate navigation on every change was the root cause of both bugs:
1. Filters applied before the user finished selecting all options.
2. Svelte 5 bind:value updates state after onchange fires, so the
   navigateWithFilters call read stale values → wrong URL params → no results.

Renamed navigateWithFilters to applyFilters (no overrides arg needed).
Added an amber Apply button next to Reset; selects now only update local
state until the user presses Apply.
v2.3.10
2026-03-28 19:44:36 +05:00
Admin
f75292f531 fix(homelab): add Google + GitHub OAuth env vars to Fider service
All checks were successful
CI / Backend (pull_request) Successful in 45s
CI / UI (pull_request) Successful in 38s
2026-03-28 19:38:11 +05:00
Admin
2cf0528730 fix(ui): show version+SHA+build time in footer; fix env not reaching runtime image
Some checks failed
CI / Backend (push) Successful in 51s
CI / UI (push) Successful in 27s
Release / Docker / caddy (push) Failing after 23s
Release / Test backend (push) Successful in 38s
Release / Check ui (push) Successful in 39s
CI / Backend (pull_request) Successful in 28s
CI / UI (pull_request) Successful in 36s
Release / Docker / backend (push) Failing after 1m25s
Release / Docker / runner (push) Successful in 2m25s
Release / Docker / ui (push) Successful in 1m51s
Release / Gitea Release (push) Has been skipped
PUBLIC_BUILD_VERSION and PUBLIC_BUILD_COMMIT were set only in the builder
stage ENV — they were never re-declared in the runtime stage, so the Node
server started with them undefined and the badge always showed 'dev'.

Fix: re-declare all three ARGs after the second FROM and set runtime ENVs.
Add PUBLIC_BUILD_TIME (ISO timestamp from gitea.event.head_commit.timestamp)
injected via build-arg in release.yaml. Badge now shows e.g.:
  v2.3.9+abc1234 · 28 Mar 2026 14:30 UTC
v2.3.9
2026-03-28 19:33:49 +05:00
Admin
428b57732e fix(ui): resolve avatar URL from MinIO; fall back to OAuth provider URL
Some checks failed
CI / Backend (push) Successful in 50s
CI / UI (push) Successful in 34s
Release / Test backend (push) Successful in 37s
Release / Check ui (push) Successful in 45s
Release / Docker / caddy (push) Successful in 35s
CI / Backend (pull_request) Successful in 49s
CI / UI (pull_request) Successful in 40s
Release / Docker / backend (push) Failing after 52s
Release / Docker / runner (push) Failing after 58s
Release / Docker / ui (push) Failing after 55s
Release / Gitea Release (push) Has been skipped
Add resolveAvatarUrl(userId, storedValue) helper that tries MinIO first,
then falls back to the stored HTTP URL for OAuth users (Google/GitHub)
who have never uploaded a custom avatar.

Add getUserById() to pocketbase helpers for batch avatar resolution in
comments. Update all 6 call sites to use the new helper.
v2.3.8
2026-03-28 19:23:30 +05:00
Admin
61e77e3e28 ci: remove Docker builds from CI; keep vet/build/test/type-check only
All checks were successful
CI / Backend (push) Successful in 43s
CI / UI (push) Successful in 37s
CI / UI (pull_request) Successful in 35s
CI / Backend (pull_request) Successful in 1m9s
Docker image builds belong to the release workflow (tag-triggered).
CI now runs: go vet, go build (backend/runner/healthcheck), go test,
svelte-check, and UI vite build — fast feedback without Docker overhead.
Also triggers on all branches, not just main/master.
2026-03-28 19:08:17 +05:00
Admin
b363c151a5 fix(ui): fix catalogue filters in Svelte 5; improve build badge visibility
Some checks failed
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 49s
Release / Docker / caddy (push) Failing after 1m0s
CI / Test backend (pull_request) Successful in 40s
CI / Docker / caddy (pull_request) Failing after 21s
CI / Check ui (pull_request) Successful in 48s
Release / Docker / ui (push) Successful in 2m49s
Release / Docker / runner (push) Successful in 3m10s
Release / Docker / backend (push) Successful in 3m47s
Release / Gitea Release (push) Has been skipped
CI / Docker / ui (pull_request) Successful in 1m31s
CI / Docker / backend (pull_request) Successful in 3m13s
CI / Docker / runner (pull_request) Successful in 3m59s
- Catalogue filter selects: replace value= initializer with bind:value +
  onchange goto() so filters navigate immediately on change (no Apply button)
- Add selected= on each <option> for correct DOM initialisation in Svelte 5
- Build badge: give distinct bg-zinc-800 pill, visible zinc-300/400/500 text
  instead of zinc-700/zinc-800 which blended into the footer background
v2.3.7
2026-03-28 19:01:58 +05:00
Admin
aef9e04419 fix(runner): harden catalogue scrape against 429s; disable sourcemap upload
Some checks failed
Release / Test backend (push) Successful in 29s
Release / Check ui (push) Successful in 43s
CI / Test backend (pull_request) Successful in 28s
Release / Docker / caddy (push) Successful in 1m8s
CI / Docker / caddy (pull_request) Failing after 39s
CI / Check ui (pull_request) Successful in 55s
Release / Docker / runner (push) Successful in 2m22s
Release / Docker / ui (push) Successful in 2m20s
CI / Docker / backend (pull_request) Successful in 2m32s
CI / Docker / ui (pull_request) Successful in 1m28s
CI / Docker / runner (pull_request) Successful in 2m25s
Release / Docker / backend (push) Successful in 2m33s
Release / Gitea Release (push) Failing after 2s
- scraper.go: ScrapeCatalogue now uses retryGet (9 attempts, 10s base) +
  500–1500ms inter-page jitter instead of bare GetContent. ScrapeMetadata
  also switched to retryGet so a single 429 on a book page is retried rather
  than aborting the whole refresh.
- catalogue_refresh.go: per-book delay is now configurable
  (RUNNER_CATALOGUE_REQUEST_DELAY, default 2s) + up to 50% random jitter
  applied before every metadata fetch. Only metadata is scraped here —
  chapters are fetched on-demand, not during catalogue refresh. Progress
  logged every 50 books instead of 100.
- config.go / runner.go / main.go: add CatalogueRequestDelay field wired
  from RUNNER_CATALOGUE_REQUEST_DELAY env var.
- release.yaml: comment out upload-sourcemaps job and remove it from the
  release needs; GlitchTip auth token needs refreshing after DB wipe.
v2.3.6
2026-03-28 16:28:36 +05:00
Admin
58e78cd34d fix(infra): make MEILI_URL configurable; rename Discover → Catalogue in nav
Some checks failed
Release / Test backend (push) Failing after 11s
Release / Docker / caddy (push) Failing after 11s
Release / Check ui (push) Failing after 11s
Release / Docker / backend (push) Has been skipped
Release / Docker / runner (push) Has been skipped
Release / Upload source maps (push) Has been skipped
Release / Docker / ui (push) Has been skipped
Release / Gitea Release (push) Has been skipped
CI / Check ui (pull_request) Successful in 49s
CI / Docker / ui (pull_request) Successful in 1m37s
CI / Docker / caddy (pull_request) Successful in 4m4s
CI / Test backend (pull_request) Successful in 4m29s
CI / Docker / runner (pull_request) Failing after 1m27s
CI / Docker / backend (pull_request) Successful in 1m41s
- docker-compose.yml: MEILI_URL in x-infra-env was hardcoded to the local
  meilisearch container, ignoring the Doppler MEILI_URL secret entirely.
  Changed to "${MEILI_URL:-http://meilisearch:7700}" so prod reads from
  https://search.libnovel.cc while local dev keeps the container default.
- ui/+layout.svelte: rename nav + footer label from "Discover" to "Catalogue"
  (desktop nav, mobile menu, footer — all three occurrences).
v2.3.5
2026-03-28 16:15:04 +05:00
Admin
c5c167035d fix(tts): fix pocket-tts voices missing in UI and 500 on first TTS enqueue
Some checks failed
CI / Test backend (pull_request) Successful in 40s
CI / Check ui (pull_request) Successful in 45s
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 41s
Release / Docker / caddy (push) Successful in 1m8s
CI / Docker / runner (pull_request) Failing after 35s
CI / Docker / caddy (pull_request) Successful in 3m39s
CI / Docker / ui (pull_request) Successful in 1m12s
CI / Docker / backend (pull_request) Successful in 3m24s
Release / Upload source maps (push) Failing after 43s
Release / Docker / runner (push) Successful in 2m49s
Release / Docker / ui (push) Successful in 2m51s
Release / Docker / backend (push) Failing after 7m14s
Release / Gitea Release (push) Has been skipped
- Add POCKET_TTS_URL env to backend service in docker-compose.yml so
  pocket-tts voices appear in the voice selector (Doppler secret existed
  but the env var was never passed to the container)
- Fix GetAudioTask PocketBase filter using %q (double-quotes) instead of
  single-quoted string, causing the duplicate-task guard to always miss
- Fix AudioPlayer double-POST: GET /api/presign/audio already enqueues
  TTS internally on 404; AudioPlayer now skips the redundant POST and
  polls directly, eliminating the 500 from the PB unique-key conflict
v2.3.4
2026-03-28 16:02:46 +05:00
Admin
4a00d953bb feat(ui): show build version in footer; enable watchtower for caddy
Some checks failed
CI / Check ui (pull_request) Successful in 50s
CI / Docker / ui (pull_request) Failing after 38s
CI / Test backend (pull_request) Successful in 3m31s
CI / Docker / backend (pull_request) Failing after 11s
CI / Docker / runner (pull_request) Failing after 11s
CI / Docker / caddy (pull_request) Successful in 11m0s
- Footer now displays build version tag + short commit SHA (from
  PUBLIC_BUILD_VERSION / PUBLIC_BUILD_COMMIT env vars baked in at
  image build time); falls back to 'dev' in local builds
- docker-compose.yml: add watchtower label to caddy service so it
  auto-updates alongside backend/ui/runner on new image pushes
- homelab/docker-compose.yml: use locally-built kokoro-fastapi:latest
  image (consistent with actual homelab setup)
2026-03-28 15:42:22 +05:00
Admin
fe1a933fd0 feat(queue): replace PocketBase polling with Asynq + Redis
Some checks failed
CI / Docker / caddy (pull_request) Failing after 50s
CI / Check ui (pull_request) Successful in 1m5s
Release / Check ui (push) Successful in 45s
Release / Test backend (push) Successful in 1m29s
CI / Docker / ui (pull_request) Successful in 1m28s
Release / Docker / backend (push) Successful in 3m14s
CI / Test backend (pull_request) Failing after 42s
CI / Docker / backend (pull_request) Has been skipped
CI / Docker / runner (pull_request) Has been skipped
Release / Docker / caddy (push) Successful in 6m48s
Release / Docker / ui (push) Successful in 2m8s
Release / Docker / runner (push) Successful in 2m51s
Release / Upload source maps (push) Failing after 53s
Release / Gitea Release (push) Has been skipped
Introduce a Redis-backed Asynq task queue so the runner consumes TTS
jobs pushed by the backend instead of polling PocketBase.

- backend/internal/asynqqueue: Producer and Consumer wrappers
- backend/internal/runner: AsynqRunner mux, per-instance Prometheus
  registry (fixes duplicate-collector panic in tests), redisConnOpt
- backend/internal/config: REDIS_ADDR / REDIS_PASSWORD env vars
- backend/cmd/{backend,runner}/main.go: wire Redis when env set; fall
  back to legacy poll mode when unset
- Caddyfile: caddy-l4 TCP proxy for redis.libnovel.cc:6380 → homelab
- caddy/Dockerfile: add --with github.com/mholt/caddy-l4
- docker-compose.yml: Caddy exposes 6380, backend/runner get Redis env
- homelab/runner/docker-compose.yml: Redis sidecar, runner depends_on
- homelab/otel/grafana: Grafana dashboards (backend, catalogue, runner)
  and alerting rules / contact-points provisioning
v2.3.3
2026-03-28 14:32:40 +05:00
Admin
98e4a87432 feat(tts): dual-engine voice list (kokoro + pocket-tts)
Expose all available voices from both TTS engines via the /api/voices
endpoint. AudioPlayer and profile voice-selector now group voices by
engine and show a labelled optgroup. Voice type carries an engine field
so the chapter-reader can route synthesis to the correct backend.
2026-03-28 14:32:06 +05:00
Admin
9c8849c6cd fix(otel): accept full https:// URL in OTEL_EXPORTER_OTLP_ENDPOINT
Some checks failed
Release / Check ui (push) Successful in 39s
Release / Docker / caddy (push) Successful in 1m4s
Release / Test backend (push) Successful in 1m38s
Release / Docker / runner (push) Successful in 39s
Release / Docker / backend (push) Successful in 2m12s
Release / Docker / ui (push) Successful in 1m0s
Release / Upload source maps (push) Failing after 5m19s
Release / Gitea Release (push) Has been skipped
WithEndpoint expects host[:port] with no scheme. When Doppler has
https://otel.libnovel.cc the backend was crashing with 'invalid port'.
Now strip the scheme and enable TLS when prefix is https://.
v2.3.2
2026-03-27 19:38:50 +05:00
Admin
b30aa23d64 fix(homelab): pocket-tts uses locally-built image, correct start command and volumes
Some checks failed
CI / Check ui (pull_request) Successful in 35s
CI / Test backend (pull_request) Successful in 39s
CI / Docker / ui (pull_request) Successful in 1m27s
CI / Docker / backend (pull_request) Successful in 1m57s
CI / Docker / runner (pull_request) Failing after 35s
CI / Docker / caddy (pull_request) Successful in 6m14s
- pocket-tts has no prebuilt image on ghcr.io — must be built from source on homelab
- Updated image to pocket-tts:latest (local tag), add command with --host 0.0.0.0
- Add model cache volumes (pocket_tts_cache, hf_cache) so model weights survive restarts
- start_period increased to 120s (first startup downloads weights)
2026-03-27 16:29:36 +05:00
Admin
fea09e3e23 feat(tts): add pocket-tts engine alongside kokoro-fastapi
Some checks failed
Release / Test backend (push) Successful in 36s
Release / Check ui (push) Successful in 50s
Release / Docker / caddy (push) Failing after 45s
CI / Test backend (pull_request) Successful in 39s
CI / Check ui (pull_request) Failing after 11s
CI / Docker / ui (pull_request) Has been skipped
CI / Docker / caddy (pull_request) Failing after 11s
Release / Docker / backend (push) Failing after 48s
Release / Docker / runner (push) Failing after 58s
Release / Upload source maps (push) Failing after 39s
CI / Docker / backend (pull_request) Failing after 34s
CI / Docker / runner (pull_request) Failing after 30s
Release / Docker / ui (push) Successful in 2m42s
Release / Gitea Release (push) Has been skipped
- New backend/internal/pockettts package: POST /tts client for
  kyutai-labs/pocket-tts; streams WAV response and transcodes to MP3
  via ffmpeg so the rest of the pipeline stays format-agnostic
- config.PocketTTS struct + POCKET_TTS_URL env var
- runner.Dependencies.PocketTTS field; runAudioTask routes by voice name:
  pockettts.IsPocketTTSVoice (alba, marius, javert, …) → pocket-tts,
  everything else → kokoro-fastapi
- Dockerfile: runner stage switched from distroless/static to alpine:3.21
  with ffmpeg + ca-certificates installed
- homelab compose: runner gets POCKET_TTS_URL=http://pocket-tts:8000
- Doppler prd + prd_homelab: KOKORO_URL=https://tts.libnovel.cc,
  POCKET_TTS_URL=https://pocket-tts.libnovel.cc
v2.3.1
2026-03-27 16:17:13 +05:00
Admin
4831c74acc feat(observability+tts): OTel logs for backend/runner/ui; add kokoro-fastapi (GPU) and pocket-tts (CPU) to homelab
Some checks failed
Release / Check ui (push) Successful in 47s
Release / Docker / caddy (push) Successful in 48s
Release / Test backend (push) Successful in 3m24s
CI / Check ui (pull_request) Successful in 52s
CI / Test backend (pull_request) Successful in 3m6s
CI / Docker / caddy (pull_request) Failing after 38s
Release / Upload source maps (push) Failing after 33s
Release / Docker / ui (push) Failing after 2m41s
Release / Docker / backend (push) Successful in 2m48s
Release / Docker / runner (push) Failing after 1m1s
Release / Gitea Release (push) Has been skipped
CI / Docker / ui (pull_request) Successful in 1m48s
CI / Docker / backend (pull_request) Successful in 1m56s
CI / Docker / runner (pull_request) Successful in 1m45s
- otelsetup.Init now returns a *slog.Logger wired to the OTLP log exporter
  so all slog output is shipped to Loki with embedded trace IDs
- backend and runner both adopt the new OTel-bridged logger
- runner.runScrapeTask and runAudioTask now emit structured OTel spans
- ui/hooks.server.ts adds BatchLogRecordProcessor alongside existing trace exporter
- homelab: add kokoro-fastapi GPU service (ghcr.io/remsky/kokoro-fastapi-gpu)
  using deploy.resources.reservations for NVIDIA GPU, exposed internally on :8880
- homelab: add pocket-tts CPU service (ghcr.io/kyutai-labs/pocket-tts) on :8000
- runner KOKORO_URL hardcoded to http://kokoro-fastapi:8880 (fixes DNS failure
  for the stale kokoro.kalekber.cc hostname)
v2.3.0
2026-03-27 16:05:22 +05:00