A book is a folder of chapters, not a file. The scanner gained a grouping
mode so a directory of tracks becomes one item with ordered files.
- registry: MediaType.Group (file | directory). Audiobooks and music group by
directory; everything else stays one item per file.
- scanner: builds groups, upserts one item per group, marks items missing when
their directory disappears, and keeps the file-level added/updated/missing
accounting. Tracks are ordered naturally, so chapter 2 precedes chapter 10.
- natsort: one shared natural-order comparator, now used by both the scanner
and the comics module (which had its own copy).
- media: GET /items/{id}/files/{fileID} streams one specific track. It
verifies the file belongs to the item, so an item id cannot be paired with
another item's file id.
No new module was needed for playback: the polymorphic progress table already
keys on file_id, so per-chapter resume fell out of the existing design. The
web player resumes the exact track and offset.
Verified: 3 chapters grouped into one book titled "Mistborn", natural order,
range request returned 206, mismatched file id 404s, per-track progress
round-trips.
|
||
|---|---|---|
| .. | ||
| src | ||
| .gitignore | ||
| embed.go | ||
| index.html | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
Vellum web
Svelte 5 + Vite + TypeScript single-page app. It is built to a static bundle in
dist/ and embedded into the Go binary, so all asset paths are relative
(base: './' in vite.config.ts).
Commands
pnpm install
pnpm dev # dev server on :5173, proxying /api to :7788
pnpm build # writes dist/
pnpm check # svelte-check
Run the Go server on :7788 (make run from the repo root) and pnpm dev
proxies API and health requests to it, so cookies and sessions behave exactly
as they will in production.
Layout
src/
main.ts entry point
App.svelte login gate -> shell
app.css design tokens and base styles
lib/
api.ts typed client; mirrors the Go handlers
session.ts auth + library stores
nav.ts view state
components/
Login.svelte
Shell.svelte nav + view switch
Libraries.svelte library list, create, scan, delete
LibraryView.svelte item grid with covers
Reader.svelte epub.js reader with progress sync
Users.svelte admin user management
The reader resumes from a spine index, which is why progress positions are
integers: it round-trips through the polymorphic progress table without
needing a text column.