Files
2026-07-12 10:17:17 -04:00

5.7 KiB

name, description, category
name description category
music-library-management Manage local music libraries — tag, rename, and organize files with beets and mutagen. Absorbed music-renamer (mutagen-based in-place rename workflow). media

Music Library Management

Tag, rename, and organize local music files. Covers beets (music library manager) for metadata-aware workflows and mutagen for fast bulk operations when files already have clean ID3 tags.

Triggers

  • User wants to rename/tag/organize music files
  • User asks about beets, mutagen, or music file metadata
  • User has a collection of mp3/flac/m4a files that need cleanup

Prerequisites

Install beets (includes mutagen as a dependency):

pip install --break-system-packages beets

Config lives at ~/.config/beets/config.yaml.

Workflow Decision

Use beets when:

  • Files need MusicBrainz tagging (missing or wrong metadata)
  • You want to reorganize files into a standard Artist/Album/Track structure
  • You need beets' query and library features long-term
  • Small batch (<100 files) — even with MusicBrainz timeout, it's manageable

Use mutagen directly when:

  • Files already have clean ID3 tags (artist, title, album present)
  • Bulk renaming is the only goal (format change, not metadata enrichment)
  • Large batch (100+ files) — beets import is too slow per-file
  • In-place renaming (keep directory structure, just fix filenames)

Beets Workflow

Configuration (~/.config/beets/config.yaml)

directory: /path/to/music/root
library: /path/to/music/root/musiclibrary.db

import:
    copy: no
    move: no        # no for import-only; yes when ready to reorganize
    write: yes
    quiet: yes      # skip confirmation prompts

# Treat loose singles as a compilation
singletons:
    album: Singles
    albumartist: Various Artists
    compilation: yes

paths:
    singleton: %(artist)s - %(title)s
    comp: Compilations/%(album)s/%(artist)s - %(title)s
    default: %(albumartist)s/%(album)s/%(track)02d - %(title)s

Import files into the library

# Slow — hits MusicBrainz per file. Use -A (no autotag) if tags are already good.
beet import -A -q --singletons /path/to/music/dir/

Query and rename already-imported files

# Dry run: see what would change
beet ls -f '$path  ||  $artist - $title' 'query'

# Actually rename (moves per path template in config)
beet move 'query'

For in-place renaming with beets, the path template must match the directory structure. Beets always uses directory + path_template — it cannot rename within arbitrary subdirectories without moving.

Mutagen Bulk Rename

When beets import is too slow and files already have ID3 tags, use the script at scripts/bulk-rename.py. It walks a directory tree, reads artist/title from tags via mutagen, and renames in-place to Artist - Title.ext.

Linked files

  • scripts/bulk-rename.py — Bulk in-place rename using mutagen ID3 tags
  • scripts/rename_by_tags.py — Alternative rename script (absorbed from music-renamer)

The script handles:

  • Collisions (appends (1), (2) to duplicates in the same directory)
  • Special characters (strips / and null bytes)
  • Files already correctly named (skips)

Quick Rename Workflow (mutagen, absorbed from music-renamer)

For the specific use case of renaming files in-place using embedded ID3 tags (files already have good tags, just need cleaner filenames), use the script at scripts/rename_by_tags.py. It walks a directory tree, reads artist/title from mutagen, and renames to Artist - Title.ext.

Trigger for this workflow

User asks to rename/organize music files, clean up filenames, strip number prefixes from downloaded music.

Step 1 — Determine scope

CRITICAL: Confirm which directories the user wants renamed. Never assume "all music." Use find with a -regex pattern to count files with number prefixes:

find /path/to/music -type f -regex ".*/[0-9]+\. .*"

Files with number prefixes (e.g., 123. Title.mp3) are the unrenamed ones.

Step 2 — Run the rename script

Use scripts/rename_by_tags.py via execute_code. The script:

  • Walks a base directory recursively
  • Reads artist/title from ID3 tags via mutagen
  • Renames files to Artist - Title.ext in-place (same directory)
  • Skips files already in the correct format
  • Handles collisions by appending (1), (2) etc.
  • Handles slashes in artist/title by replacing with -

Step 3 — Verify

ls /path/to/music/some-folder/ | head -10
find /path/to/music -regex ".*/[0-9]+\. .*" | wc -l  # should be 0

When to use mutagen vs beets

Scenario Tool
Files already have good ID3 tags, just need renaming mutagen (scripts/rename_by_tags.py)
Files have NO tags, need to be matched against MusicBrainz beets import (with autotag)
Small batch (< 50 files) needing autotag beets import is fine
Large batch (> 100 files) mutagen — beets import will time out

User preferences

  • Ray prefers mutagen over beets for bulk renaming
  • Always confirm directory scope — don't expand beyond what was asked

Pitfalls

  • Beets import is slow: Even with -A (no autotag), beets still does per-file MusicBrainz lookups. Expect ~1-3 seconds per file. For 1000+ files, mutagen is the right choice.
  • Beets move vs in-place: beet move respects directory + path_template. It cannot do truly in-place renames within arbitrary subdirectories. For in-place renames, use mutagen or a script as above.
  • beet update: Updates metadata FROM files TO library — not the reverse. Does not update stored paths after external renames.
  • Config YAML quoting: Beets path templates use %(var)s syntax. The YAML linter may warn about unquoted % characters but beets parses them correctly.