Commit graph

3 commits

Author SHA1 Message Date
mithral
5a2c3fa090 Comic metadata via ComicVine
- comicvine provider for comics. ComicVine has no keyless tier, so the
  provider is only registered when VELLUM_COMICVINE_API_KEY is set; without it
  the server logs a note and comic enrichment completes as a no-op rather than
  erroring.
- BaseURL is injectable so the response parsing is covered by a test against a
  local server: candidate mapping, the required User-Agent, and the
  status_code=100 invalid-key case (ComicVine returns HTTP 200 for that).
- descriptions are stripped of ComicVine's embedded HTML before storage.

Verified against a fake ComicVine server, and live that a comics library
enriches cleanly with no key configured.
2026-10-09 21:47:51 -04:00
mithral
1c240449ec Music metadata via MusicBrainz
- musicbrainz provider: keyless, with the required descriptive User-Agent and
  a 1 req/s throttle so the provider cannot get us blocked. Covers come from
  the Cover Art Archive by release id.
- artistHint: directory-grouped items are stored as "Artist/Album", so the
  parent directory is used as the artist when querying. Without it the search
  for "Random Access Memories" matched an unrelated release by another artist.
- pickBest: providers return fuzzy matches, and taking candidates[0] blindly
  is how an album gets the wrong artist. A candidate is only accepted when its
  normalised title corresponds to the item's; otherwise the provider is
  recorded as notfound and the next one is tried.

Verified live: after the fix the album resolves to Daft Punk, 2013, and the
correct release id, with real cover art. Before the fix it matched a Franz
Kirmann release.
2026-10-09 21:46:28 -04:00
mithral
df740d3e1a Phase 5: job queue and metadata providers
- jobs: a table-backed queue in the same SQLite file. No Redis, no second
  process, included in the same backup. claim() is a single UPDATE...RETURNING
  so a job cannot run twice even with several workers. Failures back off
  exponentially; a missing handler fails permanently rather than retrying a
  bug.
- metadata: Provider interface plus Open Library and Google Books (both
  keyless). The enricher tries providers in registration order, falls back on
  empty, and continues past a provider error.
- migration 0004: metadata_fetch records the attempt, not just the match, so a
  rescan does not re-hammer a rate-limited API for an item that will never
  match. Errors are always retried; ok/notfound are cached for 30 days.
- enrichment writes provider_ids, updates title/year, links authors through
  people/item_people, and downloads the cover as an asset. The cover download
  runs outside the transaction: a slow image host must not hold a write lock.
- endpoints: queue enrichment per library, and inspect an item's matches.
- web: Enrich button per library.

Verified live against Open Library: "The Hobbit" matched /works/OL27482W,
title and year 1937 written, a 301x500 JPEG cover downloaded and served.
2026-10-09 21:16:07 -04:00