ENOSUCHBLOG

Programming, philosophy, pedaling.


Enjoying music curation again

Feb 21, 2022     Tags: howto, workflow    

This is a follow-up to my last post, wherein I untethered myself from Spotify and figured out how to set up Navidrome behind Nginx (as a reverse proxy).

The last post was about getting just Navidrome configured and running correctly; this post be about the other tools I’ve (re-)discovered in the past few weeks, as part of my quest to refurbish and curate my historically somewhat unstructured music collection.


Library curation and maintenance: beets

This is the big ticket item: my original music collection was >150GB spread over hundreds of individual artists, with varying degrees of:

These quality issues would have taken weeks to fix manually, with a low degree of confidence in my own process and results. Instead, I turned to beets and the beet CLI.

Beets is a large and flexible tool, one that I could dedicate an entire blog post to. Instead, I’ll limit myself to sharing my beet configuration file and walking through the behavior it controls. To whit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
directory: /path/to/my/music
library: ~/.config/beets/library.db

import:
  copy: yes

paths:
  default: $albumartists/$album/$track $title

va_name: 'Various Artists'

plugins: fromfilename duplicates fetchart badfiles scrub

badfiles:
  check_on_import: yes

fetchart:
  cautious: yes
  sources: filesystem coverart itunes amazon lastfm wikipedia

With this configuration, my single step for bringing a new album (or multiple albums, under a single directory) is:

1
$ beet import path/to/some-album

which performs the following (not necessarily in this order):

  1. Uses the badfiles plug-in to check for corruption in all audio files1 being imported;

  2. Checks for a corresponding release on MusicBrainz, and uses that release to correctly tag (or re-tag) the album’s tracks (using the fromfilename plug-in for help, when needed);

  3. Uses the scrub plug-in to remove any irrelevant metadata;

  4. Uses the fetchart plug-in to find cover art for the album;

  5. De-duplicates the album, if already present in the library.

This setup works remarkably well: MusicBrainz has accurate metadata for well over 95% of the albums that I’ve passed through beet import, meaning that normalizing and checking everything is as simple as pressing “Enter” a handful of times. See below for the handful of cases where MusicBrainz’s data falls short.

Some miscellaneous notes:

  1. I haven’t found a good way to artist and album names into their “English” or Anglicized equivalents, where appropriate2. MusicBrainz generally has this information and I’m positive that there’s a way to do it with beets, but I just don’t know it yet. The current behavior doesn’t cause crashes in Navidrome or anything like that, but it’s less convenient for text searches on a Latin alphabet keyboard.

  2. The badfiles plug-in is pretty slow, probably (from an educated guess) because it doesn’t run subprocesses in parallel batches. It’s not, however, slow enough for me to try to fix. Yet.

  3. fetchart doesn’t always succeed, which means that albums can be imported while missing album art. I cover uploading this album art to the Cover Art Archive in a section below; once uploaded, it can be brought into an already imported album via the CLI with beet fetchart.

Music players: Sublime Music and Sonixd

Navidrome’s built-in HTML5 player works nicely, but native players have distinct advantages: local caching, straightforward media key integration, gapless playback, and so forth.

I use both macOS and Linux machines on a daily basis, so I needed at least one player for each platform.

On Linux, Sublime Music was the standout choice:

A screenshot of Sublime Music, showing the "Random Albums" view

Installing Sublime Music was incredibly simple. It’s available via apt on Ubuntu 20.10+, but I’m on LTS, so I installed it via pip instead:

1
2
3
$ pip install sublime-music
# or, with extras:
$ pip install sublime-music[keyring,chromecast,server]

…which in turn required a few development dependencies from apt, which I’ve forgotten to save. But the pip install error messages will point you towards them.

I would have loved to use Sublime Music on macOS as well, but it doesn’t support it. Instead, I turned to Sonixd3, which is just as featureful and has a much richer, Spotify-like user interface:

A screenshot of Sonxid, showing the "Random Albums" view

(One minor catch: Sonixd is an Electron shell and not a “native” application, so all of the standard Electron caveats about size, memory footprint, screenreader accessibility, &c apply. Local responsiveness and performance have been excellent in my experience as a single user who doesn’t need accessibility features, but YMMV).

Both Sublime Music and Sonixd have performed admirably so far, using Navidrome’s Subsonic-compatible API for all interactions. In fact, both are leaps and bounds better than anything that existed back when I was actually using Subsonic!

Some miscellaneous notes:

Metadata management: MusicBrainz and the Cover Art Archive

As mentioned above in the context of beets: MusicBrainz is an incredible service: it’s a collaborative database of metadata for the world’s music, one that anybody can edit.

The beets auto-tagger is very good at correlating an album on disk to a MusicBrainz “release” (i.e., the album and release medium), but it isn’t infallible. In particular, it can fail because (1) the on-disk copy of the album has insufficient pre-existing metadata (or sufficiently mangled filenames) to accommodate matching, or (2) the release (and possibly even the artist!) isn’t actually known to MusicBrainz yet.

In my experience importing a couple hundred albums, the first case is significantly more common than the second. Addressing it is straightforward: beet can be told to enter a “search” mode for tagging resolution, at which point the user can enter normalized versions of the artist and album names and hope for the best. If and when that fails, the user can go directly to the MusicBrainz website, perform the search these, and enter the release’s MBID directly into the appropriate beet prompt.

The second case (legitimately missing data) is trickier, but not insurmountable: you just need to add the data to MusicBrainz! The site makes this process straightforward: after creating an account, you can click the “Editing” tab at the top of any page and select the appropriate item to add:

The "Editing" tab on MusicBrainz, showing valid editing options like "Add Artist"

Each “Add” option takes you to a slightly different web tool, which takes you step-by-step through the process of adding the appropriate metadata. The more specific tools (like “Add Release”) subsume some of the more general ones, meaning that you can use “Add Release” without worrying about whether MusicBrainz is already aware of the release’s artist — it’ll give you a chance to create a new artist at the same time.

The new metadata should be available to beets as soon as it’s saved on the MusicBrainz site — simply enter the new MBID for the release and the auto-tagger will do the rest.

As part of refurbishing my old music library, I’ve had to make a couple of dozen edits to MusicBrainz, including adding some missing artists and releases (mostly from my CD collection). You can see my edits here!

Album art

This is the other hiccup with beet: an album might have impeccable metadata, but not have an album cover associated with it.

The Cover Art Archive is the solution. It’s a sub-project of MusicBrainz, in collaboration with the Internet Archive, and can be interacted with (as an uploader) entirely through the regular MusicBrainz site.

Adding missing album art is as straightforward as going to the release for the album, clicking the “Cover Art” tab, and then clicking the “Add Cover Art” button.

The "Add Cover Art" page on MusicBrainz, showing form elements for uploading cover art and adding an edit note

Updates to the Cover Art Archive seem to take a bit longer to propagate than the rest of MusicBrainz5. However, once available, running beet fetchart will detect them and correctly fetch them for your un-decorated albums!

Ripping: abcde with a custom script

Because so much of my old music library was corrupted, I decided to re-rip nearly everything I could from my physical CD collection. The last time I did this abcde was the tool for the job, and it still is.

The invocation for ripping a CD to FLAC (or MP3) does not change, so I wrapped it up in a little script named rip, which boils down to:

1
2
3
4
5
6
7
8
9
10
11
12
13
[[ -n "${1}" ]] || fatal "Usage: $(basename "${0}") <format>"
installed abcde || fatal "Missing abcde for ripping."
installed glyrc || fatal "Missing glyrc for album art."

format=$(echo "${1}" | tr "[:upper:]" "[:lower:]")

case "${format}" in
  "mp3" ) installed lame || fatal "Missing lame for MP3 encoding." ;;
  "flac" ) installed flac || fatal "Missing flac for FLAC encoding." ;;
  * ) fatal "Unsupported format: ${format}. Maybe use abcde directly?"
esac

abcde -Vx -G -a "cddb,read,encode,tag,move,clean" -o "${format}"

With that, my workflow became:

  1. Put a CD in the tray;
  2. Run rip flac;
  3. Wait for abcde to complete and eject the CD;
  4. Repeat.

A friend of mine automated this even further with udev rules, which might be worth checking out if your library is bigger than mine (or your tolerance for manually running commands is lower).

Honorable mentions

Summary

Tagging, managing, and streaming my music library is no worse than it was in 2016 or so (the last time I tried) and, in many ways, is much better.

With everything above, I’ve managed to create a relatively ergonomic curation and listening environment on all of the computers that I use on a daily basis. Only a few outstanding tasks remain:


  1. Well, some: badfiles supports MP3 (via mp3val) and FLAC (via flac) out-of-the box. Others (like M4A) can be configured with an appropriate external tool, but I’m not aware of a good checker for M4A files. 

  2. For example, Japanese musicians who have official English band and album names, in addition to their Japanese ones. 

  3. Sonixd also appears to support Linux, but only provides AppImage builds. Perhaps I’ll try and make a Debian package for it. 

  4. I might be wrong and just missed it. 

  5. Possibly because the Cover Art Archive is actually hosted on the Internet Archive’s servers, which are separate from the rest of MusicBrainz. 


Discussions: Reddit