- Go 100%
|
|
||
|---|---|---|
| .gitignore | ||
| facets.go | ||
| go.mod | ||
| go.sum | ||
| init.go | ||
| LICENSE | ||
| main.go | ||
| media.go | ||
| README.md | ||
| RELEASE_NOTES.md | ||
| scan.go | ||
| tags.go | ||
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"]
...
99is the value used in the catalog when there is no track number available in ID3 tags. Similarly,9999is 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
APICframes in their ID3 tags, writing it to a file namedcover.jpgunless 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.