Skip to content

Repository files navigation

sanitune

MIT License Python 3.11+ CI GitHub release (latest by date) GitHub last commit

sanitune logo

CLI that scans a music library and lists or deletes tracks that match your rules: DRM-locked files, low bitrates, and other quality bars. Point it at a file or folder; filters decide what matches.

Built for bulk library cleanup. Header and tag inspection only (via mutagen); it does not decode audio or strip DRM.

Contents

What it does

  • Scan files or trees. Recursively finds common audio extensions under the paths you pass.
  • Filter by DRM. Best-effort detection for Windows Media DRM (WMA/ASF encryption objects) and common FairPlay signals (.m4p, MP4 protection atoms).
  • Filter by quality. Bitrate caps for lossy codecs (e.g. MP3 under 192 kbps), plus sample rate and bit depth for lossless/PCM.
  • List or delete. Default action lists matches. --delete removes them; combine with --dry-run to preview.
  • Reacquisition report. --report FILE writes CSV or JSONL of every match with path, why it matched, DRM label, bitrate, and action (matched / would_delete / deleted / delete_failed) so you can track what to re-rip or re-buy.
  • Terminal UI. On an interactive terminal: discovery spinner, scan progress bar, results table, and a summary panel. Piping, --json, --plain, or -q stay script-friendly (paths or JSON only).
  • JSON output. --json emits one object per match on stdout for scripting.
  • No phoning home. No analytics or metrics collection; this tool does not call home in any way.

Quick Start

Once published to PyPI:

uvx sanitune ~/Music --max-bitrate 192 --format mp3

Local development (git checkout)

While hacking on this repo, do not rely on plain uvx --from .. That command builds a wheel and caches it; source edits will not show up until the project version bumps or the uv cache is cleared. Symptom: old UX or missing features after you just changed the code.

Use one of these instead (both always run the tree on disk):

uv sync
uv run sanitune ~/Music --max-bitrate 192 --format mp3 -v

# same idea via uvx + editable install
uvx --with-editable . --from . sanitune ~/Music --drm

Confirm you are on the code you think you are:

uv run sanitune --version
uv run python -c "import sanitune.display as d; print(d.__file__)"

If you specifically want to test the packaged (non-editable) install:

# after bumping version in pyproject.toml:
uvx --from . --refresh sanitune --version
# nuclear option:
uv cache clean
uvx --from . --refresh sanitune ~/Music --drm

Filters

Flag Meaning
--drm / --no-drm Match only DRM-locked files, or only non-DRM
--format mp3,m4a,... Restrict to logical formats
--max-bitrate KBPS Lossy files at or below this bitrate
--min-bitrate KBPS Lossy files at or above this bitrate
--max-sample-rate HZ Sample rate at or below
--min-sample-rate HZ Sample rate at or above
--max-bit-depth BITS Bit depth at or below
--min-bit-depth BITS Bit depth at or above
--lossy / --lossless Codec family

Filters combine with AND. Bitrate rules apply to lossy streams only; FLAC and friends are not matched by --max-bitrate alone.

Examples

# List MP3s at or under 192 kbps
uvx sanitune ~/Music --format mp3 --max-bitrate 192

# Find DRM-locked files (WMA FairPlay-era libraries, etc.)
uvx sanitune ~/Music --drm -v

# Preview deletes
uvx sanitune ~/Music --format mp3 --max-bitrate 128 --delete --dry-run

# Delete and keep a spreadsheet of what went away (and why)
uv run sanitune ~/Music --drm --delete --report ~/Music/sanitune-deleted.csv

# Dry-run with a JSONL audit trail before you commit
uv run sanitune ~/Music --max-bitrate 128 --format mp3 --delete --dry-run \
  --report ./would-delete.jsonl

# Scripting (stdout)
uvx sanitune ~/Music --drm --json

# Force plain text (CI, logs, no rich UI)
uvx sanitune ~/Music --max-bitrate 192 --plain

Report columns

CSV/JSONL fields include: timestamp, action, path, format, codec, bitrate_kbps, sample_rate, bit_depth, drm, drm_label, drm_reason, reasons (why the filters matched), error, sanitune_version. Format is taken from the file extension (.csv / .jsonl) or --report-format.

Interactive runs show a progress bar while probing and a results table (path, format, bitrate, DRM). Use -v for a Why column. --delete requires at least one filter (or --force) so a bare delete cannot wipe a tree by accident.

Security Notice

  • Deletes are permanent. There is no trash integration. Prefer --delete --dry-run first.
  • DRM detection is heuristic. Unknown protection schemes may be missed; see SECURITY.md.

Supported formats

MP3, M4A/AAC/ALAC (MP4), WMA/ASF, FLAC, WAV, AIFF, Ogg Vorbis, Opus, WavPack, APE, Musepack, and other types mutagen recognizes. Directory walks skip video containers (.mkv, .avi, …) unless --include-video.

Status

Early (0.2). Useful for library cleanup; treat DRM results as best-effort and review deletes before running without --dry-run.

Shell completions

# bash
eval "$(sanitune --print-completion bash)"

# zsh
eval "$(sanitune --print-completion zsh)"

# fish
sanitune --print-completion fish | source
# or install permanently:
sanitune --print-completion fish > ~/.config/fish/completions/sanitune.fish

Add the eval line to your shell rc if you want it every session.

Man page

# view without installing
sanitune --print-man | man -l -

# install for the local user (example)
mkdir -p ~/.local/share/man/man1
sanitune --print-man > ~/.local/share/man/man1/sanitune.1
# ensure ~/.local/share/man is on MANPATH, then:
man sanitune

Development

uv sync --group dev
uv run pytest -v          # enforces 100% coverage of the sanitune package
uv run ruff check .
uv run ruff format --check .

See CONTRIBUTING.md for the workflow.

Changelog

See CHANGELOG.md for release history.

License

MIT; see LICENSE. PRs and constructive feedback are welcome.

Runtime dependency mutagen is GPL-2.0-or-later; redistributors of binary bundles that include mutagen should account for that license on the combined work.

About

SaniTune is a command line tool for cleaning up your music library.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages