Skip to main content

music-recognition-tool

PyPI Python Tests License: MIT

A command-line tool and Python library for batch identification of audio files. It recognizes tracks with Shazam, writes the results to file tags, and optionally renames files and sorts them into an Artist/Album directory structure.

Typical use: a large collection of files named Track01.mp3, vinyl rips, or anything a media server (Plex, Jellyfin) lists as "Unknown Artist".

Contents

Features

  • Track recognition through Shazam, with retries and a configurable number of concurrent requests.
  • Tag writing for MP3 (ID3), FLAC, OGG and Opus (Vorbis comments), and M4A (MP4 atoms): title, artist, album, year, genre.
  • Renaming from a template such as {artist} - {title}; the original file extension is always preserved.
  • Moving files into <output>/<Artist>/<Album>/.
  • Files that already have title and artist tags are skipped, and a repeated run over the same directory changes nothing.
  • Dry-run mode that reports planned changes without touching any file.
  • JSON and CSV reports.
  • Optional conversion to MP3 that keeps the source file unless deletion is requested explicitly.

Requirements

  • Python 3.10 or later.
  • FFmpeg. Required to recognize M4A, Opus, AAC and WMA files and for --convert. MP3, FLAC, OGG and WAV are recognized without it, but installing FFmpeg is recommended.
# Debian / Ubuntu
sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Windows
winget install ffmpeg

Installation

pip install music-recognition-tool

This installs the music-recognize command. To install from source:

git clone https://github.com/formeo/music_recognition.git
cd music_recognition
pip install .

Quick start

Preview the changes first, then apply them:

music-recognize ~/Music/unsorted --rename --dry-run
music-recognize ~/Music/unsorted --rename

Recognize, tag and move files into an Artist/Album tree:

music-recognize ~/Music/unsorted --rename --organize -o ~/Music/sorted

Write a report without moving files:

music-recognize ~/Music/unsorted -o report.json

How processing works

For each supported file found recursively under the given path:

  1. Skip check. A file whose tags already contain a title and an artist is skipped. --force disables this check.
  2. Conversion (only with --convert). Non-MP3 files are converted to MP3 at 320 kbit/s next to the source. The source is kept unless --delete-source is given.
  3. Recognition. The file is sent to Shazam. Failed requests are retried twice with a growing delay.
  4. Tagging. Tags are written unless --no-tag is given. Existing tags are left unchanged unless --overwrite is given.
  5. Renaming and moving. With --rename, the file name is built from the template. With -o DIR, the file is moved to DIR, or with --organize to DIR/<Artist>/<Album>/ (DIR/<Artist>/ when the album is unknown). If the target name is taken by another file, a suffix (1), (2), … is added. A file that is already at its target path is not touched.

Up to --concurrent files are recognized at the same time. Recognition results are cached in ~/.music_recognition/cache.db.

Command-line reference

music-recognize PATH [options]

PATH is a file or a directory. Directories are scanned recursively.

Option Default Description
-o, --output PATH — Output directory for moved files. If PATH ends in .json or .csv, a report is written instead (directory mode only).
--rename off Rename files using --template.
--template TPL {artist} - {title}.mp3 Filename template; see Filename templates.
--organize off Move files into <output>/<Artist>/<Album>/. Requires -o DIR; has no effect without it.
--no-tag — Do not write tags. Tags are written by default.
--overwrite off Replace existing tags. Also processes files that would otherwise be skipped.
-f, --force off Process files that already have title and artist tags. Their tags are kept unless --overwrite is also given.
--convert off Convert non-MP3 files to MP3, keeping the source (directory mode only).
--delete-source off With --convert: delete the source file after a successful conversion.
-c, --concurrent N 5 Maximum number of simultaneous Shazam requests.
--delay SEC 0.5 Pause after each request, per concurrent slot.
-n, --dry-run off Report planned changes without modifying files.
-v, --verbose off Debug logging and per-file results.
-q, --quiet off Warnings and errors only.
--version — Print the version and exit.

Exit codes: 0 if every file was processed without failure (for a single file: it was recognized); 1 if at least one file failed, the path does not exist, or a single file was skipped or not recognized; 130 if interrupted.

Filename templates

Placeholder Value When missing
{artist} Artist —
{title} Track title —
{album} Album Unknown
{year} Release year Unknown
{genre} Primary genre Unknown
{track} Track number 00 (Shazam does not return track numbers)
  • The file keeps its own extension. A trailing audio extension in the template (such as .mp3) is replaced by the real one, so {artist} - {title} and {artist} - {title}.mp3 both rename song.flac to Artist - Title.flac.
  • A / in the template creates subdirectories, for example {artist}/{album}/{title}.
  • In placeholder values, the characters < > : " / \ | ? * and control characters are replaced with _. Leading and trailing spaces and dots are removed, and values are truncated to 200 characters.

Supported formats

Format Recognition Tags Needs FFmpeg
MP3 yes ID3 no
FLAC yes Vorbis comments no
OGG Vorbis yes Vorbis comments no
Opus yes Vorbis comments yes
M4A yes MP4 atoms yes
WAV yes not written no
AAC yes not written yes
WMA yes not written yes

Files whose tags are not written are still recognized, renamed and moved. Use --convert if MP3 output with tags is preferred.

Reports

Reports are written in directory mode with -o report.json or -o report.csv.

  • JSON contains summary counters (total, processed, recognized, failed, skipped, success_rate, duration_seconds) and one entry per file with its original path, final path, status, error and recognized metadata.
  • CSV contains one row per file: original_path, final_path, status, artist, title, album, error.

Because -o accepts a single value, a report and an output directory cannot be produced in the same run.

Python API

The API is asynchronous.

import asyncio
from music_recognition import MusicRecognizer


async def main() -> None:
    recognizer = MusicRecognizer(
        max_concurrent=5,             # simultaneous Shazam requests
        delay_between_requests=0.5,   # pause after each request, per slot
        retry_attempts=2,             # retries after the first attempt
        use_cache=True,
        cache_path=None,              # default: ~/.music_recognition/cache.db
    )

    stats = await recognizer.process_directory(
        source_dir="/music/unsorted",
        output_dir="/music/sorted",
        write_tags=True,
        rename=True,
        rename_template="{artist} - {title}",
        organize=True,
        overwrite_tags=False,
        skip_recognized=True,
        convert_formats=False,
        delete_source=False,
        dry_run=False,
        progress_callback=lambda done, total, result: print(f"{done}/{total} {result.status}"),
    )

    print(f"{stats.recognized}/{stats.processed} recognized, {stats.failed} failed")


asyncio.run(main())
  • process_file(file_path, ...) processes a single file with the same options, except conversion. It returns a ProcessingResult.
  • recognize_file(file_path) only recognizes a file and returns a TrackInfo.
  • recognize_and_tag(path, rename=False, organize=False, output_dir=None) is a shortcut for a file or a directory with default settings.

ProcessingStats exposes total, processed, recognized, failed, skipped, success_rate, duration_seconds, results and to_dict().

Safety

  • Run with --dry-run first, and use a copy of the collection for the first real run.
  • Changes are not journaled and cannot be undone automatically. A wrong match from Shazam is written to tags and file names as is.
  • With -o DIR, files are moved, not copied.
  • No file is deleted unless --convert --delete-source is given.

Limitations

  • Recognition uses ShazamIO, an unofficial client for Shazam's private API. The API may change or rate-limit requests without notice. If requests start failing, lower --concurrent or increase --delay.
  • Matches are not verified. Short, noisy or live recordings may be misidentified.
  • Shazam returns limited metadata: no track numbers, and the album of a track is sometimes a single or a compilation.
  • Running --convert again over the same directory creates another MP3 for each source file it keeps.

Development

git clone https://github.com/formeo/music_recognition.git
cd music_recognition
pip install -e ".[dev]"
pytest

Tests that operate on real audio files require FFmpeg and are skipped without it. Shazam is mocked in tests; no network access is needed.

Changes are listed in CHANGELOG.md.

License

MIT. Built on ShazamIO, Mutagen and pydub.

Metadata

Release files for music-recognition-tool 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for music-recognition-tool 1.3.0
File Size Uploaded
music_recognition_tool-1.3.0.tar.gz 22.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for music-recognition-tool 1.3.0
File Interpreter ABI Platform
music_recognition_tool-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 43.7 kB

Release files / music_recognition_tool-1.3.0.tar.gz

Download URL music_recognition_tool-1.3.0.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
0463f2a4e21c92204f47af970f2500d35b1d1ab06483e8b0f884468664143064
BLAKE2b-256 checksum
How to use checksums
53516506219d4b04d548b21fbf80c88499bf3de1e6d9f67df4069c8d5fdcc230
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / music_recognition_tool-1.3.0-py3-none-any.whl

Download URL music_recognition_tool-1.3.0-py3-none-any.whl
Size 21.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2375652850dadd191ec8c8484b3ade5eeeacd904e856014107b75e908bcfce38
BLAKE2b-256 checksum
How to use checksums
f445ac86a8317a130a731f6f8c4dcf2f20fb73eb673417bfaa24bab298aebf66
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

1.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page