- Go scraper: add PresignAvatarUploadURL/PresignAvatarURL/DeleteAvatar to
Store interface, implement on HybridStore+MinioClient, register
GET /api/presign/avatar-upload/{userId} and /api/presign/avatar/{userId}
- SvelteKit: replace direct AWS S3 SDK in minio.ts with presign calls to
the Go scraper; rewrite avatar +server.ts (POST=presign, PATCH=record key)
- iOS: rewrite uploadAvatar() as 3-step presigned PUT flow; refactor
chip components into shared ChipButton in CommonViews.swift
Replace blocking POST /api/audio with a non-blocking 202 flow: the Go
handler immediately enqueues a job in a new `audio_jobs` PocketBase
collection and returns {job_id, status}. A background goroutine runs
the actual Kokoro TTS work and updates job status (pending → generating
→ done/failed). A new GET /api/audio/status/{slug}/{n} endpoint lets
clients poll progress. The SvelteKit proxy and AudioPlayer.svelte are
updated to POST, then poll the status route every 2s until done.
The MinIO cache key only encoded page number, so all filter combinations
hit the same cache entry and returned unfiltered results. Introduce
BrowseFilteredHTMLKey() that encodes sort/genre/status into the key
(e.g. novelfire.net/html/new-isekai-completed/page-1.html); falls back
to the original page-only key for default filters to preserve existing
cached pages.
When a book is not in the local DB and the preview endpoint is hit,
metadata and the chapter index are now saved to PocketBase in the
background. Subsequent visits load from the local store instead of
scraping live. Chapter text is not fetched until an explicit scrape job
is triggered.
Adds FromChapter/ToChapter fields to orchestrator.Config and skips out-of-range
chapters in processBook. Exposes POST /scrape/book/range Go endpoint and a
matching UI proxy at /api/scrape/range. The book detail page now shows admins
a range input (from/to chapter) and a per-chapter 'scrape from here up' button.
Adds atomic counters for books_found, chapters_scraped, chapters_skipped,
and errors. The new OnProgress callback fires after each counter update
and once more at the end of Run, giving callers a live progress feed.