# 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.jpg` gespeichert - **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 ```bash 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 ```bash # 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 ```bash 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 | – |