Skip to content

WIP: feat(admin): bake metadata into source files on disk#39

Open
bndct-devops wants to merge 1 commit into
mainfrom
feat/bake-to-file
Open

WIP: feat(admin): bake metadata into source files on disk#39
bndct-devops wants to merge 1 commit into
mainfrom
feat/bake-to-file

Conversation

@bndct-devops

Copy link
Copy Markdown
Owner

What

Adds an admin Bake to File tool that writes Tome's metadata — title, author, series, description, cover, tags — directly into the source library files on disk, complementing the existing lazy download-time cache (get_baked_path, which stays). Useful when files are consumed outside Tome: Syncthing to another device, a Calibre library on the same folder, or direct NAS browsing.

How it works

  • Whole-library background job (backend/services/bake_job.py): single, serial, cancellable, in-memory. Runs in a daemon thread so it survives the request — closing the tab or navigating away doesn't stop it, and the page reconnects to a running job by polling GET /api/admin/bake/status.
  • Byte-weighted progress + ETA (a 300 MB CBZ ≠ an EPUB, so a file-count bar would lie).
  • Per-file safety (metadata_embed.bake_to_file): validate the embed parses → write sibling .bake.tmp → fsync → atomic os.replace → recompute sha256 → set BookFile.metadata_synced_at = book.updated_at. A bad embed never clobbers the source; one bad file never aborts the run.
  • Idempotent / resumable: metadata_synced_at == updated_at makes get_baked_path() serve the raw file and makes re-runs skip already-current files (a server restart just resumes).
  • Guards: admin-only, confirm-gated, disabled on read-only mounts (library_writable()), and TOME_ALLOW_INFILE_BAKE (default true) as a hard off-switch.
  • CBZ pages are stored uncompressed during embed (_compress_for) — the main bake-time win on large comic archives.

EPUB/CBZ get full metadata + cover; PDF gets title/author/subject.

Endpoints

GET /api/admin/bake/{status,preflight}, POST /api/admin/bake/{start,cancel,dismiss} — all admin-gated; start is audited.

Migration

Additive BookFile.metadata_synced_at column via the lifespan ALTER TABLE pattern (NULL for all existing rows).

Testing

  • tests/test_bake_to_file.py (10): EPUB/CBZ happy paths, hash recompute, metadata_synced_at semantics + get_baked_path early-return, read-only guard, corrupt/raising embed leaves the original intact with no leftover .tmp, CBZ stored-not-deflated, skips.
  • Full backend suite green; npm run build clean.
  • Headless-browser e2e against a disposable instance (copied EPUBs): preflight → confirm → running → reload mid-run reconnectedStop produced a partial summary → idempotent re-run showed "already current" → 0 leftover .tmp, all files valid, OPFs rewritten with calibre:series.

Add an admin "Bake to File" tool that writes Tome's metadata (title,
author, series, description, cover, tags) directly into the library
files on disk, complementing the existing lazy download-time cache.
Useful when files are read outside Tome (Syncthing, Calibre, NAS).

Runs as a single serial, cancellable background job with byte-weighted
progress + ETA; it survives a tab close and the page reconnects to a
running job on return. Per-file safety: validate the embed parses ->
atomic tmp write + os.replace -> recompute sha256 -> set
BookFile.metadata_synced_at. get_baked_path() serves the raw file once
synced, so re-runs skip already-current files and a restart resumes.
Disabled on read-only mounts; TOME_ALLOW_INFILE_BAKE is a hard
off-switch. CBZ pages are stored uncompressed during embed to cut bake
time on large comic archives.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@bndct-devops bndct-devops changed the title feat(admin): bake metadata into source files on disk WIP: feat(admin): bake metadata into source files on disk Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant