feat(metadata): write-to-file — embedded EPUB OPF + Calibre sidecars

Phase 5a of the metadata-writer feature: the book editor gains a
"Write to file" action (admin) that persists the item's CURRENT
database metadata into the artifact on disk, so the library stays
portable to Calibre and other apps — the thing Save alone can't do.

Dispatch (services/metadata_writer.go): EPUB/KEPUB gets its embedded
OPF spliced in place (fresh dc:* block generated inside the ORIGINAL
metadata open tag; manifest/spine/guide untouched; every other zip
entry copied byte-identical in original order so mimetype stays first
and STORED; original dc:identifiers preserved — the package's
unique-identifier must keep resolving). Everything else takes a
Calibre-style sidecar: metadata.opf when the book is ALONE in its
directory (Calibre's own convention — round-trips through Calibre
too), <basename>.opf when siblings share the folder, so one book's
sidecar can never poison dir-mates' scans (the scanner now reads both,
basename first).

Safety contract: temp file + atomic rename — the original is never
truncated on failure; the generated OPF is unit-tested to ROUND-TRIP
through the scanner's own parser (write side and read side can never
disagree); metadata_overrides are deliberately kept (file and DB agree
after the write; overrides still guard against stale sidecars). The
endpoint re-extracts inline (RescanMediaItem) and reports rescan
failure separately — a failed rescan doesn't undo the write. SHA-256
changes are inherent and documented for users (Kobo/KOReader re-key).

UI: the metadata editor modal carries the file path as a data
attribute; the button confirms before mutating, labels the target
(embedded vs sidecar) and toasts the outcome. Integration tests pin
the 403, missing-file error, EPUB embed + post-write rescan title, the
lone-book metadata.opf case, and the shared-dir <basename>.opf case
with no dir-scoped litter.
This commit is contained in:
John O'Keefe committed 2026-10-27 15:36:43 -04:00
1 parent 61e5f47ec0
commit eaf1b2c8dd
13 files changed
+1591 -413

No files matched your search

+21
View File
@@ -298,6 +298,27 @@ A: Calibre Web uses the same `metadata.opf` files, so yes - Bookhoard can scan a
A: Bookhoard has its own sorting logic and doesn't import Calibre sort fields. This allows for consistent sorting across all books.
## Writing metadata back to files (admin)
The book page's metadata editor has a **Write to file** action alongside
Save. Save updates Bookhoard's database only; Write to file persists the
currently saved values into the artifact on disk, then re-extracts so
everything stays in sync:
- **EPUB/KEPUB** — the OPF embedded in the book is rewritten in place
(cover, chapters and reading position are untouched). The file's
checksum changes, so device syncs (Kobo, KOReader) re-key the book on
their next sync.
- **Everything else** (PDF, comics, folder books, audio until tag
writing ships) — a Calibre-style sidecar is written next to the file:
`metadata.opf` when the book is alone in its folder (Calibre's own
convention, so Calibre reads it too), or `<filename>.opf` when several
books share a folder, so one book's sidecar can never leak onto its
neighbours.
The write mirrors exactly what the scanner reads back, and the original
file is never touched if anything fails (temp file + atomic rename).
## Resources
- [Calibre Website](https://calibre-ebook.com/)