Music metadata is entirely absent: MusicBrainz and AudioDb are both in the box upstream #109

Closed
opened 2026-08-13 22:59:42 +02:00 by Claude · 1 comment
Collaborator

Four remote providers and two image providers upstream, none here:

  • MusicBrainzAlbumProvider, MusicBrainzArtistProvider — the identity layer. They resolve an album or an artist to an MBID, which is what everything downstream keys on, and they are the reason two rips of one album merge rather than becoming two albums.
  • AudioDbAlbumProvider, AudioDbArtistProvider — the descriptive layer: biography, album review, year, genre.
  • AudioDbAlbumImageProvider, AudioDbArtistImageProvider — cover art and artist images, which is what a music library looks like at all.

Today a music library here has whatever the tags carry and whatever folder.jpg sits beside it. Given that music is one of the three collection types this server scans, that is the largest single-library-kind gap in the project.

MusicBrainz has a rate limit upstream honours (one request a second, and a configurable server) — worth porting deliberately rather than discovering, and worth recording in the cassette so the replay does not depend on it.

ListenBrainz is in the same directory upstream and is not a metadata provider — it is a listen-submission plugin with a similar-artist provider attached. Out of scope with the rest of the plugin ecosystem.


Where to start

Six upstream providers, none written here:
MediaBrowser.Providers/Plugins/MusicBrainz/{MusicBrainzAlbumProvider,MusicBrainzArtistProvider}.cs
and MediaBrowser.Providers/Plugins/AudioDb/ (album, artist, and the two image
providers).

Order matters here more than anywhere else: MusicBrainz is the identity
layer
. It resolves an album or an artist to an MBID, and everything downstream
— AudioDb included — keys on that. It is also why two rips of one album merge
instead of becoming two albums.

Three things to port deliberately rather than discover:

  • MusicBrainz's rate limit (upstream honours one request a second, against a
    configurable server). Record it in the cassette so a replay does not depend on
    the network's manners.
  • The search-and-score path, which music needs and the film provider was able to
    skip because the fixture names ids.
  • What an album's artist credit is, which is not the same as its track artists —
    the by-name work in crates/jellyfin-app/src/scan/by_name.rs already has
    opinions about this and they have to agree.

The fixture needs an album that can be identified; today's music library is
thin, which is also why #91's albumIds/artistIds are untested.

How to know it is done

An album and an artist scanned here carry what upstream fetched into the
enriched snapshot, MBIDs included, and the cover art matches on bytes. Then the
music pages in the pinned bundle render like upstream's — that last part is the
point of the whole issue and no diff reports it.

House rules

CLAUDE.md is the short version and these are the parts that bite: tests run
under cargo nextest; upstream's source is the checkout in upstream/ at the
pin
(v12.0-rc5, 6d501ba4) and not the clone beside the repository;
generated files are regenerated rather than edited; a comment says what the code
does, not how it got there; and Dn references stay out of code and comments.
ARCHITECTURE.md decides which crate a thing goes in and which dependency edges
are illegal, DECISIONS.md says why a rule exists.

The reference pair is cargo xtask reference up (and reference provision,
which is idempotent); a run is
cargo run -p jellyfin-harness -- replay --upstream URL --ours URL --scenario FILE --out DIR,
with diff-db for the two databases. crates/jellyfin-harness/README.md says
what a diff means and what an ignore entry has to carry — every entry needs a
reason and an expiry milestone, and an adds-only history is the smell the risk
table names.

Four remote providers and two image providers upstream, none here: - `MusicBrainzAlbumProvider`, `MusicBrainzArtistProvider` — the identity layer. They resolve an album or an artist to an MBID, which is what everything downstream keys on, and they are the reason two rips of one album merge rather than becoming two albums. - `AudioDbAlbumProvider`, `AudioDbArtistProvider` — the descriptive layer: biography, album review, year, genre. - `AudioDbAlbumImageProvider`, `AudioDbArtistImageProvider` — cover art and artist images, which is what a music library looks like at all. Today a music library here has whatever the tags carry and whatever `folder.jpg` sits beside it. Given that music is one of the three collection types this server scans, that is the largest single-library-kind gap in the project. MusicBrainz has a rate limit upstream honours (one request a second, and a configurable server) — worth porting deliberately rather than discovering, and worth recording in the cassette so the replay does not depend on it. `ListenBrainz` is in the same directory upstream and is *not* a metadata provider — it is a listen-submission plugin with a similar-artist provider attached. Out of scope with the rest of the plugin ecosystem. --- ## Where to start Six upstream providers, none written here: `MediaBrowser.Providers/Plugins/MusicBrainz/{MusicBrainzAlbumProvider,MusicBrainzArtistProvider}.cs` and `MediaBrowser.Providers/Plugins/AudioDb/` (album, artist, and the two image providers). Order matters here more than anywhere else: **MusicBrainz is the identity layer**. It resolves an album or an artist to an MBID, and everything downstream — AudioDb included — keys on that. It is also why two rips of one album merge instead of becoming two albums. Three things to port deliberately rather than discover: - MusicBrainz's rate limit (upstream honours one request a second, against a configurable server). Record it in the cassette so a replay does not depend on the network's manners. - The search-and-score path, which music needs and the film provider was able to skip because the fixture names ids. - What an album's artist credit is, which is not the same as its track artists — the by-name work in `crates/jellyfin-app/src/scan/by_name.rs` already has opinions about this and they have to agree. The fixture needs an album that can be identified; today's music library is thin, which is also why #91's `albumIds`/`artistIds` are untested. ## How to know it is done An album and an artist scanned here carry what upstream fetched into the enriched snapshot, MBIDs included, and the cover art matches on bytes. Then the music pages in the pinned bundle render like upstream's — that last part is the point of the whole issue and no diff reports it. ### House rules `CLAUDE.md` is the short version and these are the parts that bite: tests run under `cargo nextest`; upstream's source is the checkout in `upstream/` **at the pin** (`v12.0-rc5`, `6d501ba4`) and not the clone beside the repository; generated files are regenerated rather than edited; a comment says what the code does, not how it got there; and `Dn` references stay out of code and comments. `ARCHITECTURE.md` decides which crate a thing goes in and which dependency edges are illegal, `DECISIONS.md` says why a rule exists. The reference pair is `cargo xtask reference up` (and `reference provision`, which is idempotent); a run is `cargo run -p jellyfin-harness -- replay --upstream URL --ours URL --scenario FILE --out DIR`, with `diff-db` for the two databases. `crates/jellyfin-harness/README.md` says what a diff means and what an ignore entry has to carry — every entry needs a reason and an expiry milestone, and an adds-only history is the smell the risk table names.
Author
Collaborator

Landed on main with batch E (6c9c399..d83f1ca).

Measured the three ways this issue asks for: the cassette regenerated beside
the answer key, an offline chain test against the rows upstream wrote, and
artwork compared on the digest rather than on dimensions. The recording is now
crates/jellyfin-app/corpus/fetched.json — one file for all four databases,
argued in D35.

A review round ran over the batch. Seven findings were fixed in d83f1ca; what
survived is filed as #154, #155 and #156.

Landed on `main` with batch E (`6c9c399..d83f1ca`). Measured the three ways this issue asks for: the cassette regenerated beside the answer key, an offline chain test against the rows upstream wrote, and artwork compared on the digest rather than on dimensions. The recording is now `crates/jellyfin-app/corpus/fetched.json` — one file for all four databases, argued in D35. A review round ran over the batch. Seven findings were fixed in `d83f1ca`; what survived is filed as #154, #155 and #156.
alex closed this issue 2026-08-16 21:49:57 +02:00
Sign in to join this conversation.
No description provided.