Tagging and managing music with beets

Last updated:

Why is metadata important?

Tagged music files come with a lot of benefits. To name just a few:

  • You know what to expect from your music without relying on mile-long filenames or navigating through a forest of directories.

  • You can easily find what you’re looking for by querying the metadata.

  • ReplayGain normalizes loudness so that your hand can rest somewhere other than the volume knob.

Beets as a music manager

If you’re new to tagging music or want to change your workflow, maybe you can use beets to manage your library. Allowing it to fetch and apply metadata from MusicBrainz makes getting those perks I mentioned before a lot easier.

To make things easier, you may like to keep the documentation for beets in a separate tab while you read this. This blog post is more of an overview; the docs are more exhaustive.

How to install beets

Beets is probably available for installation with whatever package manager your operating system uses. Here’s how to install it on OpenBSD.

# pkg_add beets

How to configure beets

By default, beets places imported music in ~/Music. If you need to change that, add the desired path to the config.yaml file like so:

directory: /path/to/music/library

Chances are that you can go straight to importing music without any further modifications. Otherwise, the documentation on configuration can help you if you run into any issues.

How to import music

To be useful, beets needs a library to work with. That means you need to import some music. Fortunately, this is very easy to do.

$ beet import /path/to/album

If the similarity score is high enough, beets tags the music automatically and moves on. Otherwise, it’ll ask for additional details.

How to query music

To sift through some of your music, use beet ls.

It’s often best to narrow down your query with the available metadata fields. This includes things like genre, artist, album, year, country, and so on.

Here’s an example where I query by genre (note that you need to use the lastgenre plugin for this to work. I mention that plugin later on).

$ beet ls genre:'Progressive Rock'

As a side note, listing available metadata fields is done with beet fields.

What plugins does beets have?

There are many high quality plugins for beets that extend its functionality. I’ll only demonstrate a fraction of what’s possible here, so make sure to read through the documentation on plugins afterward.

Album art with fetchart

If you use a minimal music player like I do, then this may not matter as much to you. However, with more full-featured media applications, missing artwork can stick out like a sore thumb.

Thankfully, there’s an easy fix for this. Add this to your config.yaml:

plugins: fetchart

Then, update the library.

$ beet fetchart

Genre metadata with lastgenre

Out of the box, beets actually doesn’t deal with genres at all because MusicBrainz doesn’t have that information. Many people consider sorting by genre an important feature to have.

To add genre information to your collection by pulling from Last.fm, put this inside your config.yaml:

plugins: lastgenre

Then, update the library.

$ beet lastgenre

Cue sheets and how to use them

Beets needs a separate file for each track to tag music, yet sometimes there’s only one FLAC file for the entire album (it can also be something other than FLAC, but for this example I’ll assume it’s a FLAC file).

The nice thing is that as long as you have a cue sheet—a text file that describes the album’s track layout with timestamps—that single FLAC file can be split into separate files by track (“cue splitting”).

Here’s how I split a file like this into multiple files given a cue sheet.

  1. Install shntool for cue splitting, and cuetools to tag the resulting files.

    # pkg_add shntool cuetools
  2. Navigate to the album in question.

    $ cd /path/to/album
  3. Split the FLAC file.

    -f points to the cue sheet. -o is the encoder, which defaults to WAV.

    By default, the output format looks like split-track01.flac. Beets will rename the files according to the metadata anyway, so the name doesn’t matter much.

    $ shnsplit -f example.cue -o flac example.flac
  4. Rename the FLAC file so that it ends in .bak.

    This is needed for the next step so that the original FLAC file won’t be targeted by cuetag.

    $ mv example.flac{,.bak}
  5. Tag the split files with the original metadata.

    ./*.flac targets all FLAC files in the current directory. See shellcheck’s wiki entry for SC2035 for an explanation of why I use ./*.flac instead of *.flac.

    $ cuetag example.cue ./*.flac
  6. If satisfied, delete the original FLAC file.

    $ rm example.flac.bak
  7. Now that everything is split into tracks, you can import the music.

    $ beet import .

Scripting cue splitting

Given that this is a bit tedious, I wrote a small shell script to take care of splitting FLAC files for me. splitflac is used like so:

$ splitflac example.cue example.flac

By default, splitflac doesn’t delete the original FLAC file. To do so on a successful split, pass -d.

$ splitflac -d example.cue example.flac