How I’m Streaming Music

2026-05-30

In an earlier post I wrote that I was planning to use Jellyfin for music streaming. I was, but that plan changed. The client landscape for Jellyfin wasn’t really strong enough for my liking, and overall I got the impression that the music experience on Jellyfin is a little less polished. Fortunately for me, this market is well served by a few other self-hostable services.

The one that I chose is Navidrome. It is dead easy to install, and after setting it up [a couple of months ago][navidromecommit] I have not looked back. I have client applications installed on everything I use, and it integrates nicely with last.fm. I’m happy as a clam.

Navidrome is great and I recommend it, but I didn’t write this blog post to wax romantic about Navidrome. What’s more interesting is what Navidrome doesn’t do, and hence what we need to use something else for. Playing music with Navidrome works great. However, it opts out entirely of library management, and that workflow is complex enough that I’m writing this post for my own benefit, more than anyone else’s.

Library Management

Navidrome maintains an extremely narrow focus on playing music only. Its library is built entirely from metadata tags of the audio files in its library. You point it at a directory, and it scans it for files, ignoring all directories and file names on its way. This means that if you want to rename a song or update an album artist, you need to do that in the file’s metadata before adding it to Navidrome.

This is a good thing, and honestly a courageous stand against feature creep by the maintainers. It also forces users to maintain a good library, which I like a lot. It’s like forcing me to clean my room before going out to play with my friends.

And helpfully enough, Navidrome has a really good documentation page explaining how tags are used, and how you can tag your own library, going as far to recommend several tools.

Introducing Beets

I chose beets, which is a command line app that bills itself as “the media library management system for obsessive music geeks”. I don’t want to get ahead of myself, but beets might be my favourite open source project of all time.

While beets is awesome, the learning curve is steep. I really recommend reading the documentation thoroughly before getting into it. That’s not the chore it sounds like because this project’s documentation is immaculate. It’s written by a real person who is funny and knows what they are talking about. It’s not generated, it includes personal apologies for rough edges, it explains the thinking that led to things working the way they do, and it was truly a pleasure to read. I couldn’t shut up about how good these docs were while I was doing this. This page on the autotagger is I think the best time I’ve ever had reading documentation.

To give a high level overview, beets maintains a library for you, which is a directory that contains audio files. Alongside the file tree, it also maintains a SQLite database on disk. I have a directory in my home called Music Import, and I dump new audio files into that. From there, I run beet import ./Music\ Import and it does its magic. That magic is essentially divining metadata from the files based on their file names, directory grouping, and existing tags, and then searching for things against Musicbrainz’ database, and updating the tags so everything is complete and correct.

Where I need to fix things up manually, it pops me into $EDITOR, and I can update the tags that are relevant. This was particularly useful with a lot of my dad’s music, which is not available on Musicbrainz and which he had not tagged up to my standards.

The configuration I had for beet to do this is this:

directory: /srv/media/music
library: /srv/media/music/beets.db
import:
  move: true
plugins:
  - musicbrainz
  - edit

That’s literally it! I might extend this sometime with their recommended plugins for lyrics and artwork, although artwork is something Navidrome can actually source for itself, and I don’t find a huge amount of value in lyrics. I’m not even sure if Navidrome or the client apps I use support them!

I wrote this post to server primarily as a reference for me when I buy a new record and need to import some music, because it happens infrequently enough that I don’t have it committed to memory. I’m also cleaning house on topics because I will soon be deploying Jellyfin to my server. The story of that is currently a draft, and this post started as a section there that I promoted.