Skip to main content

Friendly command-line music-metadata editor and Python library

Project description

mudio

mudio is a powerful, friendly command-line music metadata editor and Python library. It provides a unified API for handling metadata across MP3, FLAC, M4A, and more, making batch processing and automation simple and safe.

Features

  • Unified API: Write code once, run it on MP3, FLAC, M4A, WAV, OGG, and OPUS.
  • Batch Processing: robust CLI for processing thousands of files.
  • Parallel Execution: Automatically uses multi-threading for large batches.
  • Safety First: Built-in backup system, dry-run mode, and careful validation.
  • Powerful Operations:
    • Find & Replace: Regex-supported search and replace in tags.
    • Mass Edits: Set, overwrite, append, prefix, or clear tags.
    • Filtering: Apply changes only to files matching specific criteria (e.g. artist="The Beatles").

Supported Formats

  • MP3 (.mp3) - ID3v2.3/v2.4
  • FLAC (.flac) - Vorbis Comments
  • M4A / MP4 (.m4a, .mp4) - MP4 Tags
  • Ogg Vorbis (.ogg)
  • Opus (.opus)
  • WAV (.wav)

Installation

pip install mudio

CLI Usage

Simple: Update metadata for files

# Set album name for all MP3 files
mudio *.mp3 --operation write --fields album --value "Greatest Hits"

Advanced: Conditional batch processing with backup

# Fix title formatting for 1990s Rock tracks, with backups and regex
mudio /music --recursive --backup ./backups \
  --filter-regex --filter "date=^199" --filter "genre=Rock" \
  --operation find-replace --fields title --find "\s+" --replace " " --regex

💡 Tip: Use --dry-run to preview changes before applying them.

Python Library Usage

Simple: Read and write metadata

from mudio.processor import process_file
from mudio.operations import write

# Update a single file with automatic verification
result = process_file(
    "song.mp3",
    ops=[write('artist', 'The Beatles')]
)
print(f"Success: {result['passed']}")  # True if successful

Advanced: Batch processing with operations

from mudio.processor import process_files
from mudio.operations import write, enlist, find_replace
from pathlib import Path

# Process multiple files with complex operations
results = process_files(
    Path('music').rglob('*.flac'),
    ops=[
        enlist('genre', 'Rock;Classic'),           # Add genres if not present
        find_replace('title', r'\s+', ' ', regex=True),  # Normalize whitespace
        write('albumartist', 'Various Artists')
    ],
    filters=[('date', '^199', True)],  # Only 1990s tracks (regex)
    backup_dir='./backups',
    max_workers=4
)

print(f"Updated {sum(r['passed'] for r in results)} files")

Environment Variables

You can configure mudio's default behavior using environment variables:

  • MUDIO_SCHEMA: Set default schema for reading metadata (canonical, extended, or raw). Default: extended.
  • MUDIO_MAX_WORKERS: Default thread count for parallel processing.
  • MUDIO_VERBOSE: Default verbosity (0 or 1).
  • MUDIO_NAMESPACE: Namespace for custom MP4/M4A fields (default: com.apple.iTunes). Setting this to something else (e.g. org.myproject) allows isolating your custom tags.
# Example: Use extended schema by default (canonical + custom fields)
export MUDIO_SCHEMA=extended
python your_script.py

Behavior Notes

Field Handling (All Formats)

mudio normalizes metadata to a case-insensitive canonical schema and applies consistent frame/value rules across formats.

Reading

  • Canonical fields: Tags that differ only by case or alias are merged via alias mapping (e.g., GENRE, genre, tcongenre).
  • Custom fields: Unrecognized (non-canonical) keys are normalized to small snake case ([a-z0-9_]). Non-alphanumeric characters are replaced with _. Alternative casings are merged (e.g., MyField, my-fieldmy_field).
  • Frame-level deduplication: If multiple frames for a field contain the same ordered list of values (after normalization), only the first is kept.
  • Intra-frame duplicates: Duplicates within a single frame are preserved.
  • Distinct frames: Frames with different value sequences are preserved and flattened in first-seen order.

Example - Custom Field Reading:

# File has tags: "MyCustomField", "my-custom-field", "MYCUSTOMFIELD"
# All merge to a single key on read
fields = sm.read_fields(schema='extended')
# Result: {'my_custom_field': ['value1', 'value2', 'value3'], ...}

Writing

  • Canonical fields: Input keys are normalized via alias mapping and merged before write. Each canonical field is written once to its format-specific native tag (e.g., ID3 TIT2, MP4 ©nam, Vorbis TITLE). Aliases are not written.
  • Custom fields: Keys are sanitized to caps snake case ([A-Z0-9_]). Non-alphanumeric characters are replaced with _.
  • Value collapse: All values for a field are emitted according to the target format's conventions, without duplicating equivalent aliases.
  • Deterministic output: Ordering reflects first occurrence after merge and deduplication.

Example - Custom Field Writing:

# Writing with various custom key formats
sm.write_fields({
    'my-custom-field': ['value1'],  # Written as: MY_CUSTOM_FIELD
    'AnotherField': ['value2'],      # Written as: ANOTHERFIELD
    'some.special!key': ['value3']   # Written as: SOME_SPECIAL_KEY
})

This ensures consistent behavior across file types while preventing casing/alias duplicates.

Canonical Fields Reference

The following canonical fields are recognized by mudio. All aliases (including case variations) map to the canonical field name:

Canonical Field Recognized Aliases
title title, tit2
artist artist, tpe1
album album, talb
albumartist albumartist, album_artist, tpe2, aart
genre genre, tcon
comment comment, comm
composer composer, tcom
performer performer, performers, perf, tpe3
date date, year, originaldate, tdrc, tory, tdat
track track, tracknumber, trck
totaltracks totaltracks, tracktotal
disc disc, discnumber, tpos
totaldiscs totaldiscs, disctotal

Note: All comparisons are case-insensitive. For example, TITLE, Title, and title all map to title.

Comparison with Alternatives

vs. Mutagen

  • Mutagen is the low-level library that mudio uses. It is powerful but requires learning different APIs for ID3, Vorbis, and MP4 tags.
  • mudio abstracts these differences. Use mudio if you want a simple, unified API (e.g. sm.write_fields({'title': ...}) works on everything). Use mutagen if you need byte-level control or support for obscure frame types.

vs. music_tag

  • music_tag is a library primarily for Python scripts, offering a dictionary-like interface. It is excellent for simple script usage.
  • mudio offers similar library features but includes a robust CLI for batch processing, filtering, and safety operations (backups, dry-runs) out of the box.

vs. Beets

  • Beets is a complete library manager with a centralized database, autotagger, and plugin system. It implies a workflow where it "owns" your library.
  • mudio is a stateless tool. It modifies files directly without a database. Use mudio for quick fixes, batch scripting, or if you prefer managing your file structure manually.

vs. Picard

  • MusicBrainz Picard is a GUI application focused on matching files to the MusicBrainz database.
  • mudio is a CLI/Library tool. It's better for automation, headless servers, or mass-editing tags based on patterns rather than database matching.

vs. EyeD3

  • EyeD3 is excellent but specific to MP3/ID3.
  • mudio supports FLAC, M4A, OGG, and more with the same commands.

Development

# Install dependencies
pip install -e ".[dev]"

# Run tests
pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mudio-3.1.1.tar.gz (45.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mudio-3.1.1-py3-none-any.whl (41.8 kB view details)

Uploaded Python 3

File details

Details for the file mudio-3.1.1.tar.gz.

File metadata

  • Download URL: mudio-3.1.1.tar.gz
  • Upload date:
  • Size: 45.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for mudio-3.1.1.tar.gz
Algorithm Hash digest
SHA256 bb1f71aef62b1bdf9cbd01745fb0a6ae824fe4a578147d37dfd6ef583bc9bacc
MD5 2b6eaa9fb02360c207efaae970273789
BLAKE2b-256 a8508bf1a0b609e35f8f6b2ce5c5a4cf4a197b4adeb5ec3f5623b32b13724519

See more details on using hashes here.

File details

Details for the file mudio-3.1.1-py3-none-any.whl.

File metadata

  • Download URL: mudio-3.1.1-py3-none-any.whl
  • Upload date:
  • Size: 41.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for mudio-3.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5797f6fa3610c66f20f346c5203e5eee598342cd00366b04b2a6681be7191517
MD5 a47467957bafba8381311cdb1491fa2f
BLAKE2b-256 bf1f5d39ce9f65ce8082587407da498af79e2516739b85c85df527df946da675

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page