Vervollständigt die Informationen über ein Musik-Datei-Verzeichnis, passt die Dateinamen und Metadaten der Dateien entsprechend an.
- Python 100%
- --except filters albums by directory name (glob or substring, repeatable) - README.md: new options table entries, new cover sources, updated pipeline, corrected test count (33), added batch example - BEDIENUNGSANLEITUNG.md: new options table, sections E (batch+except), F (--status), LASTFM_API_KEY env var, corrected test count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .gitignore | ||
| BEDIENUNGSANLEITUNG.md | ||
| cover_handler.py | ||
| executor.py | ||
| hint_extractor.py | ||
| metadata_resolver.py | ||
| models.py | ||
| music_enricher.py | ||
| README.md | ||
| scanner.py | ||
| test_suite_enricher.py | ||
Music Metadata Enricher
KI-gestützter Musik-Metadaten-Enricher für Jellyfin-Bibliotheken.
Analysiert Album-Verzeichnisse, vervollständigt Tags, besorgt Cover-Art und benennt Dateien optional nach einem einheitlichen Schema um — vollständig ohne API-Key nutzbar, mit lokalem LLM (Ollama) für lückenhafte Metadaten.
Features
- Lokale Analyse — Verzeichnisname, Dateinamen, bestehende ID3/FLAC/M4A-Tags, Tracklist-Textdateien (.txt, .htm, .html)
- YouTube-ID-Erkennung — erkennt YouTube-Video-IDs im Dateinamen, holt Titel,
Uploader und Kapitel automatisch via
yt-dlp - OCR Back-Cover — liest Tracklisten aus
back.jpg/ Booklet-Bildern via Ollama Vision (qwen3-vl, minicpm-v) - MusicBrainz-Lookup — Textsuche + AcoustID-Fingerprinting (optional)
- Discogs-Fallback — Cover + vollständige Trackliste bei MusicBrainz-Misses
- iTunes Search API — Cover-Fallback (gratis, kein Key)
- Last.fm — Cover + Tracklist-Fallback (kostenloser API-Key)
- LLM-Reasoning — Ollama (lokal, kostenlos) → OpenRouter (DeepSeek V3) für unklare / widersprüchliche Metadaten
- Cover-Art — lokal (JPG/PNG/WebP) → MusicBrainz Cover Art Archive (front + back)
→ Discogs → iTunes Search API → Last.fm; einbetten in MP3/FLAC/M4A;
WebP wird automatisch zu JPEG konvertiert, Cover immer als
folder.jpggespeichert - Tag-Schreiben — title, artist, album, albumartist, tracknumber, discnumber, date, genre, label (mutagen, ID3v2.4)
- Umbenennen — normiertes Dateinamen-Schema mit Unterstrichen (Pop und Klassik)
- M3U-Playlist — wird nach dem Umbenennen automatisch neu generiert
- Backup — Sicherungskopien vor jeder Änderung
- CSV-Report — vollständiges Protokoll aller Änderungen
- Interaktiver / Auto-Modus — mit Konfidenz-Schwellwert
Voraussetzungen
pip install mutagen musicbrainzngs pyacoustid discogs_client \
Pillow requests tqdm beautifulsoup4
sudo apt install libchromaprint-tools # fpcalc für AcoustID-Fingerprinting
sudo apt install yt-dlp # YouTube-Metadaten (optional)
| Paket | Zweck | Optional? |
|---|---|---|
mutagen |
Tags lesen/schreiben | nein |
musicbrainzngs |
MusicBrainz-API | ja |
pyacoustid |
AcoustID-Fingerprinting | ja |
discogs_client |
Discogs-API | ja |
Pillow |
Cover-Bildgröße prüfen, WebP→JPEG | ja |
requests |
Cover-Art-Download | ja |
tqdm |
Fortschrittsbalken | ja |
beautifulsoup4 |
HTML-Tracklisten parsen | ja |
fpcalc |
Audio-Fingerprinting-Binary | ja |
yt-dlp |
YouTube-Metadaten + Kapitel | ja |
Für LLM-Reasoning wird ein laufender Ollama-Server erwartet (Port 11434).
Empfohlenes Modell: qwen3:8b (5 GB). OCR: qwen3-vl:latest.
Umgebungsvariablen (optional)
| Variable | Beschreibung | Default |
|---|---|---|
OLLAMA_HOST |
Ollama-Server-URL | http://localhost:11434 |
OLLAMA_RESOLVE_MODEL |
LLM für Metadaten-Reasoning | qwen3:8b |
OLLAMA_OCR_MODEL |
Vision-Modelle für OCR (kommagetrennt) | qwen3-vl:latest,minicpm-v:latest,deepseek-ocr:latest |
OPENROUTER_API_KEY |
OpenRouter-Fallback (DeepSeek V3) | – |
ACOUSTID_API_KEY |
AcoustID-Fingerprinting | – |
DISCOGS_TOKEN |
Discogs-API | – |
LASTFM_API_KEY |
Last.fm Cover + Tracklist-Fallback | – |
CLI
music_enricher.py [Optionen] PFAD [PFAD ...]
music_enricher.py --album PFAD [Optionen]
| Option | Beschreibung |
|---|---|
--dry-run |
Vorschläge anzeigen, nichts schreiben |
--auto |
Kein interaktiver Review-Schritt |
--confidence FLOAT |
Min-Konfidenz für --auto (default: 0.85) |
--rename |
Dateien nach Schema umbenennen |
--embed-cover |
Cover-Art in Audiodatei einbetten |
--backup PFAD |
Backup-Verzeichnis vor Änderungen |
--report PFAD |
CSV-Report der Änderungen |
--no-fingerprint |
AcoustID-Fingerprinting überspringen |
--no-api |
Keine externen API-Calls (MusicBrainz, Discogs, OCR) |
--no-cover |
Kein Cover-Art-Download |
--album PFAD |
Einzelnes Album verarbeiten |
--no-tqdm |
Fortschrittsanzeige deaktivieren |
--status |
Bibliotheksstatus anzeigen (fehlende Cover, schlechte Tags) |
--skip-complete |
Alben mit Cover + guten Tags überspringen (Batch-Optimierung) |
--except PATTERN |
Album ausschließen (Glob oder Substring, mehrfach verwendbar) |
Verwendung
# Einzelnes Album — Dry-Run, nur lokale Analyse
python3 music_enricher.py --dry-run --no-api \
--album ~/Musik/Abba_-_Greatest_Hits
# Mit MusicBrainz-Lookup und Ollama-LLM
python3 music_enricher.py --dry-run \
--album ~/Musik/Bach_Organ_-_Peter_Hurford
# Vollständig: Tags + Cover einbetten + umbenennen, mit Backup und Report
python3 music_enricher.py --embed-cover --rename \
--backup /tmp/musik_backup \
--report report.csv \
~/Musik
# Auto-Modus: nur Vorschläge ≥ 90% Konfidenz anwenden
python3 music_enricher.py --auto --confidence 0.90 \
--embed-cover --rename --backup /tmp/backup \
~/Musik
# Batch-Lauf: vollständige Alben überspringen, bestimmte ausschließen
python3 music_enricher.py --auto --confidence 0.5 --rename --embed-cover \
--no-fingerprint --skip-complete \
--except 'Abba*' --except Eigene_Aufnahmen \
~/Musik
# Bibliotheksstatus anzeigen (kein Schreiben)
python3 music_enricher.py --status ~/Musik
# Album mit YouTube-IDs in Dateinamen (yt-dlp holt Titel + Kapitel automatisch)
python3 music_enricher.py --auto --confidence 0.1 --rename --embed-cover \
--album ~/Musik/Die_Bergvagabunden_Am_Lagefeuer.audio
Verarbeitungs-Pipeline
Album-Verzeichnis
│
▼
1. AlbumScanner — Dateitypen klassifizieren (Audio, Bild, Tracklist, Playlist)
│
▼
2. HintExtractor — lokal, keine API
├─ Verzeichnisname → Artist, Album, Jahr
├─ Dateinamen → Tracknummer, Artist, Titel (YouTube-ID wird entfernt)
├─ ID3/FLAC-Tags → bestehende Werte
├─ Tracklist .txt/.htm → Tracklisten parsen (4-stufiges Matching)
├─ YouTube-IDs → Titel, Uploader, Kapitel via yt-dlp
└─ OCR Back-Cover → Tracklist aus back.jpg via Ollama Vision
│
▼
3. MetadataResolver
├─ AcoustID → MusicBrainz via Fingerprint
├─ Textsuche → MusicBrainz-API
├─ Discogs → Cover + vollständige Trackliste
├─ Last.fm → Trackliste-Fallback
└─ LLM-Reasoning → Ollama lokal → OpenRouter (DeepSeek V3)
│
▼
4. CoverHandler — lokal → MusicBrainz CAA (front+back) → Discogs → iTunes → Last.fm → einbetten
│
▼
5. ReviewStep — interaktiv oder --auto mit Konfidenz-Schwellwert
│
▼
6. Executor — Backup → Tags → Cover → Umbenennen → M3U → Report
Konfidenz-Modell
| Quelle | Bonus |
|---|---|
| AcoustID-Match ≥ 90% | +0.20 |
| MusicBrainz via Fingerprint | +0.25 |
| MusicBrainz-Texttreffer (Score/100) | +0.30 × Score |
| Discogs | +0.15 |
| LLM-Reasoning (Ollama/OpenRouter) | +0.10 |
| Lokale Hints (Ordner-/Dateiname, YouTube) | +0.05 |
Dateinamen-Schema (mit --rename)
Pop/Default — Leerzeichen als Unterstriche, Teile durch _-_ getrennt:
01_-_ABBA_-_Dancing_Queen.mp3
2-07_-_Die_Bergvagabunden_-_Hohe_Tannen.flac
Klassik — Performer und Komponist explizit getrennt:
01_-_Peter_Hurford_-_Johann_Sebastian_Bach_-_Toccata_And_Fugue_In_D_Minor_BWV_565.mp3
01_-_Gardiner_-_Bach_-_Kantate_BWV_147_-_English_Baroque_Soloists.flac
Schema: [D-]TT_-_Performer_-_Komponist_-_Werk[_-_Orchester_Dirigent].ext
Bei Single-Disc entfällt die Disc-Nummer. Bei Multi-CD wird sie immer gesetzt (1-01, 2-01 etc.).
Projektstruktur
Music_Metadata_Enricher/
├── music_enricher.py Haupt-CLI, Pipeline-Orchestrierung
├── models.py Dataclasses: AlbumScan, AlbumHints, TrackProposal, …
├── scanner.py Dateisystem-Scanner, Typ-Klassifikation
├── hint_extractor.py Dateiname/Tag/Tracklist/OCR/YouTube-Auswertung
├── metadata_resolver.py MusicBrainz + Discogs + Ollama/OpenRouter LLM
├── cover_handler.py Cover-Art: Suche, WebP-Konvertierung, Download, Einbettung
├── executor.py Backup, Tag-Schreiben, Umbenennen, M3U, CSV-Report
└── test_suite_enricher.py 33 Unit-/Integrationstests
Tests
python3 test_suite_enricher.py
# 📊 33/33 Tests erfolgreich
Unterstützte Formate
| Format | Tags | Cover-Einbettung |
|---|---|---|
| MP3 | ID3v2.4 (EasyID3) | APIC-Frame |
| FLAC | Vorbis-Comments | METADATA_BLOCK_PICTURE |
| M4A/AAC | MP4-Tags | covr-Atom |
| Sonstige | mutagen generic | – |