- Go 100%
| cmd | ||
| internal | ||
| utils | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| README.md | ||
musicctl
A CLI for music library automation. Recursively lists music files, reads their metadata, and copies/links them into a structured output directory using metadata-derived path templates.
Installation
go install source.idionaut.net/varun/musicctl@latest
Or build from source:
git clone <repo>
cd homecli
go build -o out/musicctl .
Commands
list
Recursively lists music files under one or more directories.
musicctl list [flags] <path> [<path>...]
| Flag | Default | Description |
|---|---|---|
-e, --exts |
mp3,m4a,m4b,m4p,alac,flac,ogg,dsf |
File extensions to include |
-n, --limit |
0 (no limit) |
Maximum number of files to print |
Example
musicctl list ~/Music
musicctl list -e flac,alac -n 50 ~/Music
metadata
Reads metadata from music files and prints it as tab-separated values. Accepts file paths as arguments or via stdin (pipe-friendly).
musicctl metadata [flags] [file...]
| Flag | Default | Description |
|---|---|---|
-c, --cols |
fullpath,album,artist,title |
Columns to output |
-H, --header |
false |
Print a header row |
Processing is parallelised across all CPU cores; output order matches input order.
Available columns
| Category | Columns |
|---|---|
| File identity | path, fullpath, format, file_type, container |
| Core tags | title, subtitle, artist, album_artist, album, year, date, original_date, comment, lyrics, genre |
| Multi-value tags | artists, genres, composers, performers |
| Track/disc | track_number, track_total, disc_number, disc_total |
| Extended tags | description, narrator, publisher, label, copyright, grouping, series, series_part, isbn, asin, isrc, barcode, catalog_number, language |
| MusicBrainz IDs | mb_track_id, mb_album_id, mb_artist_id |
| Audio properties | duration, sample_rate, bitrate, bit_depth, channels, codec, lossless, vbr |
| ReplayGain | rg_track_gain, rg_track_peak, rg_album_gain, rg_album_peak |
Example
musicctl metadata -H -c artist,album,title,duration ~/Music/track.flac
musicctl list ~/Music | musicctl metadata -c fullpath,codec,bitrate,lossless
copy
Copies (or hard-links / symlinks) music files into an output directory, organising them by a path template expanded from each file's metadata.
musicctl copy [flags] [file...]
| Flag | Default | Description |
|---|---|---|
-o, --output |
(required) | Destination root directory |
--format |
%artist%/%album%/%title%.%ext% |
Path template using %token% placeholders |
--mode |
hardlink |
How to place files: copy, hardlink, symlink |
-f, --force |
false |
Overwrite existing destination files |
--dry_run |
false |
Print destination paths without writing |
Path template tokens
%artist%, %album_artist%, %album%, %title%, %ext%, %year%, %genre%, %track_number%, %disc_number%, %date%, %codec%, %label%
Missing tag values fall back to sensible defaults (Unknown Artist, Unknown Album, etc.). Track numbers are zero-padded to two digits.
Example
# Dry-run: preview where files would land
musicctl copy --dry_run -o /tmp/out ~/Music/unsorted/
# Organise by codec then artist/album
musicctl copy -o ~/Music/sorted \
--format "%codec%/%artist%/%album%/%track_number% - %title%.%ext%" \
~/Music/unsorted/*.flac
# Hard-link an entire library (pipe from list)
musicctl list ~/Music | musicctl copy -o ~/MusicOrganised --mode hardlink
Global flags
| Flag | Default | Description |
|---|---|---|
--dry_run |
false |
No mutating changes (supported by copy) |
-b, --batch |
false |
Non-interactive / batch mode |
Composing commands
All commands are pipe-friendly — list and metadata write one path per line to stdout, which can be piped directly into metadata or copy.
# Find all lossless files and print their ReplayGain values
musicctl list -e flac,alac ~/Music \
| musicctl metadata -c fullpath,rg_track_gain,rg_album_gain
# Copy only the files returned by list
musicctl list ~/Downloads/new-music \
| musicctl copy -o ~/Music --mode hardlink
License
See LICENSE.