Feb 21, 2022 Tags: howto, music, workflow
This post is at least a year old.
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.
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):
Uses the badfiles
plug-in to check for corruption in all audio files1 being imported;
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);
Uses the scrub
plug-in to remove any irrelevant metadata;
Uses the fetchart
plug-in to find cover art for the album;
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:
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.
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.
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
.
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:
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:
(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:
Sonixd doesn’t tell the Subsonic API to scrobble playbacks by default; I had to enable it in the “settings” pane. Not a huge deal, but something to be aware of. Sublime Music, by contrast, unconditionally scrobbles every play (assuming that scrobbling is enabled on the server).
Sonixd supports “soft” gapless playback, i.e. gapless by virtue of track crossfades. This works pretty well in practice (I have no complaints), but some purists might object that it’s not “real” gapless playback.
Sublime Music’s local cache can be confused by deletions/renames of music on the server side. I haven’t experienced any crashes because of stale cache state so far, but I did have to clear out the entire local cache after doing a complete reindex:
1
$ rm -r ~/.local/share/sublime-music
(I’m not sure why Sublime Music puts its cache there, instead of in ~/.cache
as XDG suggests.)
Sublime Music supports gapless playback via the libmpv
player (which is the default),
but that support is not in a release yet. Until that release happens, you’ll need to do a local
build of master
(which is easy, since it’s just a poetry
-managed Python project).
Here is the corresponding merge request,
which will hopefully be included in a release soon!
Neither Sonixd nor Sublime Music appears4 to support the Subsonic API’s
startScan
endpoint, which
allows a user to trigger a re-scan/index of the server. This isn’t a huge deal, since Navidrome
periodically re-scans on its own and supports manual re-scanning via the web client. But it
would be nice to have!
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:
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!
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.
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!
abcde
with a custom scriptBecause 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:
rip flac
;abcde
to complete and eject the CD;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).
Glyr is both a library (libglyr
) and a CLI tool (glyr
) for
discovering music metadata, including album covers. It’s basically the beets metadata engine, made
modular and usable outside of a managed beets library. I didn’t need to use it thanks to the
fetchart
plug-in, but it’s been a lifesaver in the past!
mp3val
is what the badfiles
plug-in uses internally
to validate MP3 files. It’s been unmaintained for over a decade, but it’s still provided by
every major distribution and functions just fine.
One of the nice things about mp3val
is that it also supports fixing MP3 files, via
mp3val -f <INPUT> [INPUT ...]
. The badfiles
plugin doesn’t expose this (there’s an
open issue here!), but it’s easy enough to do
from the CLI before running beet import
.
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:
Mobile playing: I almost never listen to music on my phone, but there are a large number of Subsonic-compatible iOS clients. I haven’t tried many of them yet, but the ones that I have tried haven’t been great — they remind me of the state of affairs back when Subsonic itself was still the dominant “Subsonic-compatible” server.
Some kind of radio: I’d like to be able to serve up a randomized playlist from my Navidrome instance as a kind of public internet radio. I think this would be pretty easy to do; it’s just a matter of hooking up the Subsonic API to Icecast or something similar.
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. ↩
For example, Japanese musicians who have official English band and album names, in addition to their Japanese ones. ↩
Sonixd also appears to support Linux, but only provides AppImage builds. Perhaps I’ll try and make a Debian package for it. ↩
I might be wrong and just missed it. ↩
Possibly because the Cover Art Archive is actually hosted on the Internet Archive’s servers, which are separate from the rest of MusicBrainz. ↩