Skip to main content

avalon

Analyzes, tags, and organizes a music library:

  • BPM/key extraction, mood/genre/energy descriptors via Essentia
  • ID3/Vorbis/MP4 tag normalization
  • cover art, format conversion

Runs once over a folder or as a watching daemon. MusicBrainz/Discogs reconciliation is left to Picard.

Requirements

  • Python 3.10–3.11 (see the essentia-tensorflow pin in pyproject.toml for why)
  • uv
  • ffmpeg on PATHbrew install ffmpeg / apt install ffmpeg

Install

git clone <repository-url> && cd avalon
uv sync

OR

pip install libavalon

First run downloads Essentia's models (~26.5MB) to ~/.cache/avalon/models/.

Usage

# tag in place
uv run avalon analyze ~/Music/Downloads --recursive

# reorganize into {artist}/{album}/{title}.{ext}
uv run avalon analyze ~/Music/Downloads --recursive --dest ~/Music/Library

# convert lossless sources, cap bit depth/sample rate (lossy sources untouched)
uv run avalon analyze ~/Music/Downloads --dest ~/Music/Library \
    --convert-lossless-to aiff --max-bit-depth 16 --max-sample-rate 48000

# watch continuously, -v so you can see it working (backfills on startup)
uv run avalon watch ~/Music/Downloads --dest ~/Music/Library -v

# backfill a large library faster with 8 concurrent worker processes
uv run avalon analyze ~/Music/Downloads --recursive --dest ~/Music/Library --workers 8

# see what's actually in a file's tags
uv run avalon inspect ~/Music/Library/Artist/Album/01\ -\ Title.aiff

Full flag list: avalon analyze --help / avalon watch --help.

How it works

flowchart TD
    src[source file]
    src --> analyze[essentia analysis]
    src --> conv{convert?}
    conv -->|yes| ffmpeg
    conv -->|no| copy[copy in place]
    analyze --> write[write tags + art]
    ffmpeg --> write
    copy --> write
    write --> out[output file]

Analysis runs against the original file, before any conversion. Canonical fields (title/artist/album/genre/bpm/key) only fill in when missing — nothing gets overwritten unless you pass --force-reanalyze.

--workers N runs analysis in N separate worker processes instead of one at a time — each has its own Essentia/TensorFlow session, so results never cross between files. Destination-path collisions (e.g. two files with missing tags both falling back to the same Unknown Artist/Unknown Album path) are still resolved from a single process before any work is handed to a worker, so numbering stays correct under --workers too.

Tags

Two avalon-owned tags per file: a short headline (bpm:128;key:Am;camelot:8A; energy:0.71;genre:Techno, in COMM/DESCRIPTION/desc, configurable via --headline-tag/--headline-format) and an extended tag with the full descriptor roster (TXXX:AVALON_ANALYSIS / a Vorbis field / an MP4 atom).

MusicBrainz/Discogs/AcoustID reconciliation isn't handled by avalon — run Picard over the library separately for that.

Development

uv sync --extra test
uv run pytest

Download files

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

Source Distribution

libavalon-0.0.3.tar.gz (58.3 kB view details)

Uploaded Source

Built Distribution

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

libavalon-0.0.3-py3-none-any.whl (28.2 kB view details)

Uploaded Python 3

File details

Details for the file libavalon-0.0.3.tar.gz.

File metadata

  • Download URL: libavalon-0.0.3.tar.gz
  • Upload date:
  • Size: 58.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for libavalon-0.0.3.tar.gz
Algorithm Hash digest
SHA256 8c26cd07e6a9a01bc6e7b8e4579721a42efc3b340448690f4bab3a01bbf1e1b4
MD5 e3583495ea35131d1506fdf2837bcd9e
BLAKE2b-256 cf6a344e906ba3553558ed2516bf89a367a9ff3dfd6912652a0c85c7e58c856d

See more details on using hashes here.

File details

Details for the file libavalon-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: libavalon-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 28.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for libavalon-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 52d7f7f73c84fb38e6d68b4647b0d14fcef349f0c09c6dd99cb69ba1c8ecc54c
MD5 783e5d96e1d165416e66a233ce2d3999
BLAKE2b-256 8e3d28b6607a93743fc46fc6abae98af32cf343fcb3b20db9af05f38a74077e7

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