Skip to main content

Essentia-powered genre & mood auto-tagger for the music-manager suite

Project description

essentia-autotagger

Essentia-powered genre & mood auto-tagger that writes clean, multi-value tags for Picard, Navidrome, Jellyfin, and friends.

Python 3.11 License: MIT Ruff

essentia-autotagger analyses your library with Essentia's Discogs-EffNet models and writes discrete, multi-value genre and mood tags, the way modern players expect them.

Features

  • Player-correct tags. Each genre/mood is written as a separate value (repeated Vorbis comments, null-separated ID3v2.4 frames, MP4 value lists, …), never a "Rock; Hip Hop" blob, so Picard/Navidrome surface them as individual, browsable tags.
  • Non-destructive. Only the genre and mood fields are touched; existing comments and other tags are never altered, and already-tagged files are skipped unless you pass --overwrite.
  • Hierarchy-aware genres. Rock---Alternative Rock becomes Rock + Alternative Rock, so you can browse by broad or specific genre.
  • Wide format support. FLAC, MP3, Ogg/Opus, MP4/M4A, WMA, WavPack, APE, AIFF/WAV, DSF, and more (full mapping below).
  • Tunable & scriptable. TOML config + CLI flags, exclude lists, a genre-normalization map, output caps, parallel workers, a dry-run existing → proposed diff, and an optional JSON report.

Requirements

  • Linux or WSL. The analysis backend (essentia-tensorflow) ships Linux-only wheels and bundles TensorFlow.
  • conda / mamba. Used to pin Python 3.11 (the newest interpreter essentia-tensorflow supports) without touching your system Python.
  • ~23 MB of disk for the models, downloaded once.

Quick start

From a clone of this repository:

# 1. Create and activate the environment (Python 3.11 + dependencies)
conda env create -f environment.yml      # or: mamba env create -f environment.yml
conda activate essentia-autotagger

# 2. Fetch the Essentia models once (~23 MB)
essentia-autotagger download-models             # have ~/essentia_models already? add --from-dir ~/essentia_models

# 3. Preview what would be written; nothing is modified
essentia-autotagger /path/to/Album --dry-run

# 4. Tag for real
essentia-autotagger /path/to/Album

Models are stored per-user at ~/.local/share/essentia-autotagger/models.

Usage

# Whole library, parallel, replacing existing genre/mood tags
essentia-autotagger /srv/Music --workers 6 --overwrite

# A single file (e.g. driven by a file-watcher)
essentia-autotagger "/srv/Music/Artist/Album/03 Song.flac"

# Genres only, stricter threshold, at most 3 values, with a run log
essentia-autotagger /srv/Music --no-moods --genre-threshold 25 --max-genres 3 --log-dir ./logs

# Dry run that also exports predictions + confidences as JSON
essentia-autotagger /srv/Music/Album --dry-run --report ./preview.json

A dry run shows the change for every file so you can review before committing:

$ essentia-autotagger "Artist/Album/03 Song.flac" --dry-run
essentia-autotagger [DRY RUN] - models: ~/.local/share/essentia-autotagger/models
Found 1 audio file(s)
03 Song.flac
   genres: (none)  ->  Hip Hop, Pop Rap
   moods : (none)  ->  Energetic, Happy
Done. processed=1 written=0 skipped=0 errors=0

Run with no arguments for interactive prompts. essentia-autotagger --help lists every flag.

Key options

Flag Default Description
--dry-run off Analyse and print existing → proposed; change nothing
--overwrite off Replace existing tags (otherwise already-tagged files are skipped)
--top-genres N 3 How many genre predictions to consider
--genre-threshold PCT 15 Genre confidence floor, in percent
--max-genres N 5 Cap on genre values written (0 = no cap)
--leaf-only off Write only the specific genre, not its parent
--mood-threshold PCT 0.5 Mood confidence floor, in percent
--max-moods N 3 Cap on mood values written
--workers N auto Parallel workers (0 = half the cores, 1 = sequential)
--report FILE none Write per-file predictions + confidences as JSON
--no-genres / --no-moods off Disable one side of the analysis

Configuration

Every default can be set in a TOML file (CLI flags still take precedence). Start from the example:

cp config.example.toml ~/.config/essentia-autotagger/config.toml

Search order: --config FILE$ESSENTIA_AUTOTAGGER_CONFIG~/.config/essentia-autotagger/config.toml./config.toml.

A few options are config-only:

  • exclude_genres / exclude_moods: drop labels you never want (case-insensitive), e.g. exclude_genres = ["Non-Music", "Field Recording"].
  • [tagger.genre_map]: canonicalize or merge Discogs labels into your own vocabulary, e.g. "Hip Hop" = "Hip-Hop".

Tag mapping

Each format gets the field its players expect, written as multiple discrete values:

Format Genre field Mood field
FLAC / Ogg / Opus GENRE MOOD
MP3 / AIFF / WAV / DSF TCON (ID3v2.4) TMOO (ID3v2.4)
M4A / MP4 / AAC ©gen ----:com.apple.iTunes:MOOD
WMA / ASF WM/Genre WM/Mood
WavPack / APE / Musepack Genre Mood

How it works

  1. Recursively scan for audio; skip files already tagged (unless --overwrite).
  2. Decode to 16 kHz mono (capped at --max-duration, default 5 min) and compute Discogs-EffNet embeddings.
  3. Run the genre_discogs400 and mtg_jamendo_moodtheme classification heads.
  4. Expand genres parent+leaf, apply your map/excludes, and cap the count.
  5. Write multi-value tags with mutagen. Tag writing always happens in the main process; only analysis is parallelized, so output is identical at any --workers.

Development

conda env create -f environment.yml && conda activate essentia-autotagger
pytest                                  # unit tests; ffmpeg synthesizes fixtures, no models needed
ruff check . && ruff format --check .
src/essentia_autotagger/
  cli.py            argparse entry point + interactive mode
  config.py         dataclass Config + TOML loader
  paths.py          model/config/log directory resolution (XDG)
  models.py         model download + single load_bundle()
  analysis.py       audio -> genre/mood predictions (shared by all paths)
  formatting.py     labels -> clean multi-value strings
  tagging.py        per-format multi-value read/write
  discovery.py      file scan + cheap existing-tag check
  pipeline.py       orchestration (sequential + multiprocessing)
  logging_setup.py  stdlib logging

Acknowledgements

Inspired by WB2024/Essentia-to-Metadata. Built on Essentia and its pretrained Discogs-EffNet models, with mutagen for tag I/O.

License

This project is released under the MIT License.

The Essentia models are downloaded from essentia.upf.edu and carry their own licenses: the Discogs and MTG-Jamendo models are CC BY-NC-SA 4.0 (non-commercial). Review them before commercial use or redistribution.

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

essentia_autotagger-0.1.0.tar.gz (28.9 kB view details)

Uploaded Source

Built Distribution

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

essentia_autotagger-0.1.0-py3-none-any.whl (26.2 kB view details)

Uploaded Python 3

File details

Details for the file essentia_autotagger-0.1.0.tar.gz.

File metadata

  • Download URL: essentia_autotagger-0.1.0.tar.gz
  • Upload date:
  • Size: 28.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for essentia_autotagger-0.1.0.tar.gz
Algorithm Hash digest
SHA256 afb0861a6d3648494d31fa9f462c964760c9cc17d809c0dd5ab48141eebeb68b
MD5 89465acd87ebf24cd7a08a2a2297a82b
BLAKE2b-256 f55a8cfa44efd6eb14819179d722eb60425124f57a69198638d80c1eb7251c3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for essentia_autotagger-0.1.0.tar.gz:

Publisher: release.yml on cookiephone/essentia-autotagger

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file essentia_autotagger-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for essentia_autotagger-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75da223db2c859b8971184553a7aca6efde369808a9df516ebc9e556e3fa1367
MD5 e73f540cd14ff4427e91876e02d70253
BLAKE2b-256 4fbf18997a26add773146caa4baa5ca3511a900d9f9e8000b8824c96bb50ac4f

See more details on using hashes here.

Provenance

The following attestation bundles were made for essentia_autotagger-0.1.0-py3-none-any.whl:

Publisher: release.yml on cookiephone/essentia-autotagger

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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