No description
Find a file
2026-07-08 20:32:03 +00:00
.gitignore adding gitignore 2025-06-22 00:51:16 -06:00
facets.go removing pre-facets tagGenre function 2026-05-09 13:44:58 -06:00
go.mod mod update 2026-05-17 15:34:51 -06:00
go.sum mod update 2026-05-17 15:34:51 -06:00
init.go improved help 2026-06-21 11:56:11 -06:00
LICENSE Initial commit 2025-06-08 16:06:12 -06:00
main.go add media json dump 2026-06-14 10:12:55 -06:00
media.go munge media titles on entry 2026-07-02 14:12:10 -06:00
README.md doc update 2026-06-15 11:44:07 -06:00
RELEASE_NOTES.md doc update 2026-07-08 14:31:17 -06:00
scan.go -xfix now sets track num 2026-05-12 09:37:46 -06:00
tags.go added -tnum 2026-05-10 15:08:47 -06:00

thrasher-music-tool

Management utility for the Thrasher music system.

TMT (aka "tool") is one part of the Thrasher system, which forms a complete music library management system that supports tagging music in whatever way makes sense to you, and keeps ID3 tags in sync with music catalog changes so they're always your source of truth.

Linux and Mac OS are supported.

Build

go build && sudo mv thrasher-music-tool /where/ever/in/PATH, or just go run . from this repo.

To see the brief usage reference, run thrasher-music-tool -h. For more comprehensive help, run thrasher-music-tool help, and then see the available topics. Or keep reading this doc.

Initial setup

To start using Thrasher in any capacity, a catalog of your music must be created by scanning your library of music files. And for that to happen, a minimal configuration file needs to be set up.

Config file

Create a config file at /etc/tmc.json with the following format:

{
  "musicdir": "/PATH/TO/MUSIC",
  "server": {
    "artist_cutoff": INT
  }
}

artist_cutoff specifies the number of tracks that an artist must have in the catalog to be included in the catalog's artist list. There is no "best" or "correct" value for this attribute. I use 5, but feel free to go higher or lower to be more or less restrictive with the artist quick-filter list -- you'll be able to find every track by every artist regardless.

This is all we need to get started. We'll fill out the rest of the config file when it's time to get the music service running.

Scan your music

Now run thrasher-music-tool -s to create the catalog database and do the initial scan of your music. The database file will be located at MUSICDIR/thrashermusic.db.

Anytime new music is added to MUSICDIR, run another scan to update the catalog.

Listening to music

The tool is just for managing your catalog. Use the thrasher-music-service web or mobile interfaces for playback.

Facets

One of the more unique features of Thrasher is that tracks can be assigned multiple facets in order to allow flexible classification and listening. So beyond another word for "tags", what are facets?

At a minimum, facet is the name Thrasher uses for genre, and the TCON frame of existing ID3 tags will become the initial facet for a track.

But Thasher allows arbitrarily many facets to be associated with a track. Facets therefore allow you to:

  • Assign multiple 'genres' (or moods, or subgenres, or...) to tracks
  • Classify music by cross-cutting concerns, like bands from a given city, or groups that you've seen live
  • Note tracks that are instrumentals
  • Or capture any other info you'd like to be base your listening on

"Facet" was chosen because in library science this type of classification scheme is known as "faceted".

Management of facets via the tool is covered later in this doc.

Filters

Nearly all operations other than scans require the specification of a filter, which is a compact text format that specifies which tracks from the catalog will be operated on.

At the command line, as a rule, enclose filters in singlequotes to keep the shell from parsing them. Should you need a singlequote in a filter, use your preferred technique for multi-level quoting in the shell.

Filters have a key:value format, where the key is the attribute of the track you're matching against, and the value is the value to be matched. Filter keys have a long and short form, and they are:

S Long Description
a artist Track artist
b album Track album name
f facet Facet
n num Track number within album
t title Track title/name
y year Album/track publication year

A very simple filter might be to select all tracks from

  • a given artist: 'a:ronny jordan' (filter attribute text values are treated as case-insensitive)
  • a given year: 'y:1984'

Wildcards can be used. To select all music from the 1970s:

'y:197*'

More complex filters can be constructed by combining k:v pairs with AND (&&) and/or OR (||) operators:

'f:jazz||f:rock' # legal: all tracks with facet "jazz" or "rock"
'f:jazz||rock'   # not legal; k:v pairing is required

When grouping is needed, use double-parens:

'((f:jazz||f:rock))&&y:197*' # all jazz or rock tracks from the 1970s

Managing the catalog

The tool is the only piece of Trasher which can modify the catalog, either via scans to add/remove tracks, or by running operations which modify filtered sets of tracks.

When the tool performs an operation that modifies a track in the catalog, in most cases that change will also be made to the underlying file -- preserving modification time so as not to cause false positives in future scans. This means that if you move away from Thrasher, or need to rebuild the catalog, you will still have nearly all updates that you have made.

The obvious exception to this is multiple facets, which cannot be captured in a standard way with ID3v2.4 tags, so preserving your Thrasher databse is important if you want to keep all your facet customizations.

Querying

Query operations are at the core of everything done with the tool, because filters are specified with the -qf (query filter) flag, and filters are how the tool is told which tracks to operate on.

The simplest thing to do is print the filepaths of the matching tracks, and that's done with -q:

$ thrasher-music-tool -qf 'y:197*' -q
/AC_DC/Dirty Deeds Done Dirt Cheap/01 Dirty Deeds Done Dirt Cheap.mp3
/AC_DC/Dirty Deeds Done Dirt Cheap/02 Ain't No Fun (Waiting 'Round To Be A Millionaire).mp3
/AC_DC/Dirty Deeds Done Dirt Cheap/03 There's Gonna Be Some Rockin'.mp3
...

The value of musicdir (from the config file) is elided from the paths, to avoid leaking server configuration info.

To see the catalog data for tracks, use -qp (query pretty-print):

$ thrasher-music-tool -qf 'y:197*' -qp
  1 | AC/DC                          | Dirty Deeds Done Dirt Cheap                        | Dirty Deeds Done Dirt Cheap    | 1975 | ["Rock"]
  2 | AC/DC                          | Ain't No Fun (Waiting 'Round To Be A Millionaire)  | Dirty Deeds Done Dirt Cheap    | 1975 | ["Rock"]
  3 | AC/DC                          | There's Gonna Be Some Rockin'                      | Dirty Deeds Done Dirt Cheap    | 1975 | ["Rock"]
...

-qp is the default operation, so if a filter is provided and no other op is requested, this is what you'll get back.

One of the functions in the music player UI is the 'Recent' button, which enqueues all tracks from the 25 albums most recently added to the catalog. The tool also provides this via the -qr flag, and notably, since its scope is predefined there is no need to specify a filter:

$ thrasher-music-tool -qr
 99 | L'Impératrice                  | Passengers                                         | Palais Billes ARTE Concert     | 2024 | ["Funk","Dance","Pop","Chill"]
 20 | Radio Trip                     | Gambling Man                                       | Jalapeno Funk, Vol. 13         | 2024 | ["Funk"]
 16 | Sam Redmore                    | Nagu                                               | Jalapeno Funk, Vol. 13         | 2024 | ["Funk"]
...

99 is the value used in the catalog when there is no track number available in ID3 tags. Similarly, 9999 is used when the year is missing. This is to make it easier to find tracks which need some fix-ups

There are a few more query ops available, but were implemented more for validation of catalog behavior than for day-to-day utility, so they are not covered here.

Facets

Facets are one of the central capabilities of Thrasher, so one of the central use-cases of the Tool is managing them.

Adding facets

Facets are added to tracks with -fadd. Only one facet can be added at a time, though any number of facets can be added to a track in total.

$ thrasher-music-tool -qf 'a:Jellyfish' -fadd Alternative
+ facet Alternative added to /Jellyfish/Spilt Milk/01 - Hush.mp3
+ facet Alternative added to /Jellyfish/Spilt Milk/02 - Joining A Fan Club.mp3
...

Filter values are treated as case-insensitive in queries, but the value provided to -fadd will be used exactly as you have given it. To help protect against typos, the tool requires verification (via also specifying -yes) when adding a facet that doesn't already exist in the catalog:

$ thrasher-music-tool -qf 'a:florence*' -fadd jazz  # will fail; 'Jazz' is the extant facet
'jazz' not in current facets set; rerun with -yes to add

If a facet is already set on a track, the request becomes a no-op:

$ thrasher-music-tool -qf 'b:Catgirl*' -fadd Game
= 'Game' already set on /CityGirl/Catgirl/City Girl - CATGIRL Soundtrack - 01 Catgirl.mp3
= 'Game' already set on /CityGirl/Catgirl/City Girl - CATGIRL Soundtrack - 02 Mopmop's Theme.mp3
...

In the case where a track has no facets defined, meaning that there was no TCON value in the ID3 tags during scanning, the TCON (aka "genre") field will be set to the value you are adding as a facet.

$ thrasher-music-tool -qf 'b:Os Catedraticos 73'
  1 | Eumir Deodato                  | Arranha Ceu (Skyscrapers)                          | Os Catedraticos 73             | 1973 | []
  2 | Eumir Deodato                  | Flap                                               | Os Catedraticos 73             | 1973 | []
  3 | Eumir Deodato                  | Rodando Por Ai (Rudy's)                            | Os Catedraticos 73             | 1973 | []
...

$ thrasher-music-tool -qf 'b:Os Catedraticos 73' -fadd Jazz
I no facets; setting ID3 genre on /Eumir Deodato/OsCatedraticos73/Eumir Deodato - Os Catedraticos 73 - 01 Arranha Ceu (Skyscrapers).mp3
+ facet Jazz added to /Eumir Deodato/OsCatedraticos73/Eumir Deodato - Os Catedraticos 73 - 01 Arranha Ceu (Skyscrapers).mp3
I no facets; setting ID3 genre on /Eumir Deodato/OsCatedraticos73/Eumir Deodato - Os Catedraticos 73 - 02 Flap.mp3
+ facet Jazz added to /Eumir Deodato/OsCatedraticos73/Eumir Deodato - Os Catedraticos 73 - 02 Flap.mp3
...

Removing facets

Facets are removed from tracks with -frm. Only one facet can be removed at a time.

As with adding facets, if an attempt is made to remove a facet which doesn't exist in the catalog (including correct casing), that will fail:

$ thrasher-music-tool -qf 'b:a boy named charlie brown' -frm jazz
'jazz' not in current facets set; cannot remove

And trying to remove a facet which isn't set on a track is a no-op:

$ thrasher-music-tool -qf 'b:a boy named charlie brown' -frm Rock
= facet 'Rock' not set on /Vince Guaraldi Trio/A Boy Named Charlie Brown/Baseball Theme.mp3
= facet 'Rock' not set on /Vince Guaraldi Trio/A Boy Named Charlie Brown/Blue Charlie Brown.mp3
...

Facet removal has a special case: the tool will refuse to remove the last facet set on a track:

$ thrasher-music-tool -qf 'b:a boy named charlie brown' -frm Jazz
! 'Jazz' is only facet; refusing to remove from /Vince Guaraldi Trio/A Boy Named Charlie Brown/Baseball Theme.mp3
! 'Jazz' is only facet; refusing to remove from /Vince Guaraldi Trio/A Boy Named Charlie Brown/Blue Charlie Brown.mp3
...

When all conditions for facet removal are met, the facet will be removed from the catalog and ID3 tags will be updated if needed:

$ thrasher-music-tool -qf 'b:*night in paris' -frm Funk
- facet 'Funk' removed from /PhilCollins/Phil_Collins-A_Hot_Night_in_Paris/01.Sussudio.mp3
= genre on source file not set to 'Funk'; no change needed
- facet 'Funk' removed from /PhilCollins/Phil_Collins-A_Hot_Night_in_Paris/02.Thats_All.mp3
= genre on source file not set to 'Funk'; no change needed
...

$ thrasher-music-tool -qf 'b:give love at christmas' -frm Miscellaneous
- facet 'Miscellaneous' removed from /The Temptations/Give Love At Christmas/01 - Give Love On Christmas Day [Explicit].mp3
U genre set to 'Xmas' on /The Temptations/Give Love At Christmas/01 - Give Love On Christmas Day [Explicit].mp3
- facet 'Miscellaneous' removed from /The Temptations/Give Love At Christmas/02 - The Christmas Song.mp3
U genre set to 'Xmas' on /The Temptations/Give Love At Christmas/02 - The Christmas Song.mp3
...

Other data

In addition to facets, the Tool can also modify many other aspects of track data. Here's the relevant portion of the online help:

  -talb string
        update tag: album title
  -tart string
        update tag: artist
  -ttit string
        update tag: track title
  -tyr int
        update tag: release year (default 9999)

All these ops affect both the Catalog and the source files, so that everything is kept in sync. And as with facet operations, a query must be set to target the tracks which will be affected.

Fixing files with poor tags

Modern storefronts and ripping tools are very reliable about tagging files, but if your collection contains older data, you may have some tracks which have little or no ID3 data. You can check for this by connecting to the music DB with sqlite3 and running this query:

select trk, title, album, year, facets from tracks where artist = ''

If this returns tracks, and your library is arranged in a /ARTIST/ALBUM structure, you can automate improving things with the -xfix operator.

Note: -xfix ignores current ID3 and database values! Understand how it works before running! Doublecheck your location in the filesystem before running!

Go to the directory where the problematic MP3s are located and run the tool with -xfix. It will update ID3 tags and database entries for all MP3s in the directory, using the name of the current directory as the album title, the name of the parent directory as the artist name, and the filenames (minus .mp3) as track titles. This is imperfect, but it's a lot less work than doing it manually.

More about scanning

The scan function was introduced at the beginning of this document because it's the mechanism for initial creation of a Catalog. It's also the main way in which the Catalog is kept up-to-date, so here's a fuller discussion.

As mentioned previously, a "regular" scan can be done at any time with -s. This will do three things:

  • Add records to the Catalog for any files which have been added to the music directory since the last time a scan was run
  • Extract album art from files which have APIC frames in their ID3 tags, writing it to a file named cover.jpg unless this file already exists
  • Update the records of any files which have been changed since their modification timestamp in the Catalog (which is interpreted as modification by another utility)

Scans normally use filesystem modification times, and will skip directories/subtrees if they appear up-to-date. If this is failing to detect something, run a slower full file scan with -sf rather than -s.

The -sd (scan-for-deleted) operation does the inverse of other scans: it scans the Catalog to and checks that the backing file for every entry still exists. Tracks whose files are missing will be deleted from the Catalog.

Backups

There is no backup operation within the Tool. However, since the Thrasher db is a Sqlite database, you can simply copy it in its entirety, or do something like the following in a script:

sqlite3 /PATH/TO/music.db '.dump' > music.sql && bzip2 music.sql

Then copy the bz2 file to the location/server/etc. of your choice.