No description
Find a file
Varun Santhosh 904f7f542c update help
2026-05-15 22:34:34 +01:00
cmd update help 2026-05-15 22:34:34 +01:00
internal fix default copy path 2026-05-15 22:30:23 +01:00
utils refactor 2026-05-09 18:14:00 +01:00
.gitignore fixes 2026-05-04 18:54:14 +01:00
go.mod using taglib 2026-05-09 19:16:02 +01:00
go.sum using taglib 2026-05-09 19:16:02 +01:00
LICENSE GPLv3 license 2026-05-09 13:22:33 +01:00
main.go mod fixes 2026-05-04 19:51:37 +01:00
README.md default hardlink 2026-05-09 13:20:39 +01:00

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.