I've written at length about my scrobbling implementation on my site. Until now I'd managed the metadata for my music manually, editing it on macOS before adding it to Navidrome. That gave me direct control, ate time and came with quite a bit of tedium.

I'd seen beets mentioned a few times as a tool to programmatically manage and apply metadata. I've wanted to use it, but cutting over a collection with nearly 800 artists and over 5,000 albums was a lot. But, as with most bad ideas I have, this one stuck with me.

One habit I'd gotten into while managing music was to assign splits to a single artist. If I had both artists in my collection, I'd split them into two albums, one for each artist. For collaborative albums I'd have either a unique artist for the collaboration or (incorrectly) assign it to whichever artist I preferred.

Fixing this meant, for starters, a database migration. My schema supported only a 1:1 relationship between artists and albums. Now an album like When No Birds Sang can be properly associated with both Nothing and Full of Hell. So I have artists in my Navidrome library whose only release is a split for which I may or may not have included their tracks—this makes my teeth itch, but I can live with it. I can't do anything about these artists in Navidrome, but I've filled out the album data on my site with ghost tracks. I pull the full tracklist from MusicBrainz to populate these releases and highlight them as missing.

Connecting things

My music files sit in Navidrome, my listening data and scrobbles sit in my site's database. Scrobbles are sent from the former to the latter. Previously, I'd matched listens based on name alone. I've updated my artist, album and track schema to store their respective Navidrome IDs. For about 90% of my library, Navidrome derives that ID from the release's MusicBrainz ID and the rest are built from the tags.

Aligning metadata

I've added a Library section to the music portion of my custom CMS.1 There are Inbox, Sync and Retag tabs. New music is uploaded in the Inbox tab. It's routed to an inbox directory on my Navidrome server. A scan is run against the inbox content. Exact matches are applied automatically; otherwise I pick from a list of likely releases. Once a release is picked, the album is tagged and scanned into Navidrome.

Once Navidrome has picked up the album, I move to the Sync tab and run a check job which looks for an existing match in my site's database. If there's no existing record and no errors from the check job, I can sync the new release to my site. Plays are then tied to the album by ID.

The Retag tab is where I manage music metadata. When I initially moved my tag management to beets, I spent much of my time here. The actual music scans run on my Navidrome server and report matches and misses back. Artists that need attention are flagged here for me to review. Again, with hundreds of artists and thousands of albums, this took a while. If I want to change the match for an album, I can revert to the previously selected release or edit the metadata manually. If I edit the album record, I can choose to write the edits to the tags on the audio and, when the tags are rewritten, I sync the updates back to my site.

Edge cases

Before storing IDs with albums, I'd hit edge cases when scrobbling plays for artists who had multiple albums with the same title (looking at you American Football). This generally worked in practice, but the absence of mismatches was more luck than proper implementation. Now, if a scrobble arrives without an ID and its title matches none of the artist's albums, or more than one, the site creates a new record I can merge into the right one.

This was one of those projects with a ton of up-front work that should pay off over time. Previously, everything I added I would download, tag manually, upload to the S3 bucket where I keep my music using rclone, and then it would get backed up to an archive, scanned in and synced. Now, I upload FLAC files once, beets tags them, converts them to MP3 and imports them, then copies the originals to my archive. I tend to run metadata syncs manually when I import or retag something, but those run nightly as well. Imports are easier, tags are correct and scrobbles are more reliable.