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-tensorflowpin inpyproject.tomlfor why) - uv
ffmpegonPATH—brew 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file libavalon-0.0.5.tar.gz.
File metadata
- Download URL: libavalon-0.0.5.tar.gz
- Upload date:
- Size: 61.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4264574245c32b5f9c34ef2e0e8b6eaf862f20bf02b1fa7981fab9c7b58499d0
|
|
| MD5 |
6c215d0ae6b4db22ec36c47f0e3eaedf
|
|
| BLAKE2b-256 |
a995f7d74b3ead6eb3999d206e246b1beafac2197de9e6c9b413d3efb23232a3
|
File details
Details for the file libavalon-0.0.5-py3-none-any.whl.
File metadata
- Download URL: libavalon-0.0.5-py3-none-any.whl
- Upload date:
- Size: 29.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9375a8546d89dc5dae30fe75af9c1883817c9d7722cfd1bad3c1121e516f7f3
|
|
| MD5 |
dd92f1b423f636baeb543c97ecdd7694
|
|
| BLAKE2b-256 |
e5c8bcc3fe287c9d67180cca9d48d1c76b0f6560044794e09252563d67297189
|