Music_Metadata_Enricher/README.md
dschlueter 0ca05e91d4 Add --except PATTERN option and update documentation
- --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>
2026-04-29 11:38:52 +02:00

246 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 | |