Update README: Ollama/OpenRouter LLM, OCR, YouTube, WebP, underscore schema

- Replace Claude API references with Ollama → OpenRouter chain
- Add YouTube ID detection, OCR back cover, WebP cover support
- Fix filename schema examples (spaces → underscores, _-_ separator)
- Add classical naming schema with Performer/Composer distinction
- Add Ollama env vars (OLLAMA_HOST, OLLAMA_RESOLVE_MODEL, OLLAMA_OCR_MODEL)
- Update pipeline diagram with OCR and YouTube steps
- Add yt-dlp to prerequisites

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-04-29 06:03:39 +02:00
commit 5c7b6759ff

View file

@ -4,7 +4,7 @@ KI-gestützter Musik-Metadaten-Enricher für Jellyfin-Bibliotheken.
Analysiert Album-Verzeichnisse, vervollständigt Tags, besorgt Cover-Art und Analysiert Album-Verzeichnisse, vervollständigt Tags, besorgt Cover-Art und
benennt Dateien optional nach einem einheitlichen Schema um — vollständig ohne benennt Dateien optional nach einem einheitlichen Schema um — vollständig ohne
API-Key nutzbar, mit optionaler Claude-KI für lückenhafte Metadaten. API-Key nutzbar, mit lokalem LLM (Ollama) für lückenhafte Metadaten.
--- ---
@ -12,13 +12,20 @@ API-Key nutzbar, mit optionaler Claude-KI für lückenhafte Metadaten.
- **Lokale Analyse** — Verzeichnisname, Dateinamen, bestehende ID3/FLAC/M4A-Tags, - **Lokale Analyse** — Verzeichnisname, Dateinamen, bestehende ID3/FLAC/M4A-Tags,
Tracklist-Textdateien (.txt, .htm, .html) 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) - **MusicBrainz-Lookup** — Textsuche + AcoustID-Fingerprinting (optional)
- **Discogs-Fallback** — bei MusicBrainz-Misses - **Discogs-Fallback** — bei MusicBrainz-Misses
- **Claude API** — Reasoning-Schritt für unklare / widersprüchliche Daten (optional) - **LLM-Reasoning** — Ollama (lokal, kostenlos) → OpenRouter (DeepSeek V3) für
- **Cover-Art** — lokal → MusicBrainz Cover Art Archive → einbetten in MP3/FLAC/M4A unklare / widersprüchliche Metadaten
- **Cover-Art** — lokal (JPG/PNG/WebP) → MusicBrainz Cover Art Archive → einbetten
in MP3/FLAC/M4A; WebP wird automatisch zu JPEG konvertiert
- **Tag-Schreiben** — title, artist, album, albumartist, tracknumber, discnumber, - **Tag-Schreiben** — title, artist, album, albumartist, tracknumber, discnumber,
date, genre, label (mutagen, ID3v2.4) date, genre, label (mutagen, ID3v2.4)
- **Umbenennen**`01 - Artist - Title.ext` / `2-07 - Artist - Title.ext` (Multi-CD) - **Umbenennen** — normiertes Dateinamen-Schema mit Unterstrichen (Pop und Klassik)
- **M3U-Playlist** — wird nach dem Umbenennen automatisch neu generiert
- **Backup** — Sicherungskopien vor jeder Änderung - **Backup** — Sicherungskopien vor jeder Änderung
- **CSV-Report** — vollständiges Protokoll aller Änderungen - **CSV-Report** — vollständiges Protokoll aller Änderungen
- **Interaktiver / Auto-Modus** — mit Konfidenz-Schwellwert - **Interaktiver / Auto-Modus** — mit Konfidenz-Schwellwert
@ -29,8 +36,9 @@ API-Key nutzbar, mit optionaler Claude-KI für lückenhafte Metadaten.
```bash ```bash
pip install mutagen musicbrainzngs pyacoustid discogs_client \ pip install mutagen musicbrainzngs pyacoustid discogs_client \
anthropic Pillow requests tqdm Pillow requests tqdm beautifulsoup4
sudo apt install libchromaprint-tools # fpcalc für AcoustID-Fingerprinting sudo apt install libchromaprint-tools # fpcalc für AcoustID-Fingerprinting
sudo apt install yt-dlp # YouTube-Metadaten (optional)
``` ```
| Paket | Zweck | Optional? | | Paket | Zweck | Optional? |
@ -39,21 +47,28 @@ sudo apt install libchromaprint-tools # fpcalc für AcoustID-Fingerprinting
| `musicbrainzngs` | MusicBrainz-API | ja | | `musicbrainzngs` | MusicBrainz-API | ja |
| `pyacoustid` | AcoustID-Fingerprinting | ja | | `pyacoustid` | AcoustID-Fingerprinting | ja |
| `discogs_client` | Discogs-API | ja | | `discogs_client` | Discogs-API | ja |
| `anthropic` | Claude API | ja | | `Pillow` | Cover-Bildgröße prüfen, WebP→JPEG | ja |
| `Pillow` | Cover-Bildgröße prüfen | ja |
| `requests` | Cover-Art-Download | ja | | `requests` | Cover-Art-Download | ja |
| `tqdm` | Fortschrittsbalken | ja | | `tqdm` | Fortschrittsbalken | ja |
| `beautifulsoup4` | HTML-Tracklisten parsen | ja |
| `fpcalc` | Audio-Fingerprinting-Binary | 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) ## Umgebungsvariablen (optional)
| Variable | Beschreibung | | Variable | Beschreibung | Default |
|----------|-------------| |----------|-------------|---------|
| `ANTHROPIC_API_KEY` | Claude API (Reasoning für Metadaten-Lücken) | | `OLLAMA_HOST` | Ollama-Server-URL | `http://localhost:11434` |
| `ACOUSTID_API_KEY` | AcoustID-Fingerprinting | | `OLLAMA_RESOLVE_MODEL` | LLM für Metadaten-Reasoning | `qwen3:8b` |
| `DISCOGS_TOKEN` | Discogs-API | | `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 | |
--- ---
@ -74,7 +89,7 @@ music_enricher.py --album PFAD [Optionen]
| `--backup PFAD` | Backup-Verzeichnis vor Änderungen | | `--backup PFAD` | Backup-Verzeichnis vor Änderungen |
| `--report PFAD` | CSV-Report der Änderungen | | `--report PFAD` | CSV-Report der Änderungen |
| `--no-fingerprint` | AcoustID-Fingerprinting überspringen | | `--no-fingerprint` | AcoustID-Fingerprinting überspringen |
| `--no-api` | Keine externen API-Calls | | `--no-api` | Keine externen API-Calls (MusicBrainz, Discogs, OCR) |
| `--no-cover` | Kein Cover-Art-Download | | `--no-cover` | Kein Cover-Art-Download |
| `--album PFAD` | Einzelnes Album verarbeiten | | `--album PFAD` | Einzelnes Album verarbeiten |
| `--no-tqdm` | Fortschrittsanzeige deaktivieren | | `--no-tqdm` | Fortschrittsanzeige deaktivieren |
@ -84,11 +99,11 @@ music_enricher.py --album PFAD [Optionen]
## Verwendung ## Verwendung
```bash ```bash
# Einzelnes Album — Dry-Run, kein API-Key nötig # Einzelnes Album — Dry-Run, nur lokale Analyse
python3 music_enricher.py --dry-run --no-api \ python3 music_enricher.py --dry-run --no-api \
--album ~/Musik/Abba_-_Greatest_Hits --album ~/Musik/Abba_-_Greatest_Hits
# Mit MusicBrainz-Lookup # Mit MusicBrainz-Lookup und Ollama-LLM
python3 music_enricher.py --dry-run \ python3 music_enricher.py --dry-run \
--album ~/Musik/Bach_Organ_-_Peter_Hurford --album ~/Musik/Bach_Organ_-_Peter_Hurford
@ -100,12 +115,12 @@ python3 music_enricher.py --embed-cover --rename \
# Auto-Modus: nur Vorschläge ≥ 90% Konfidenz anwenden # Auto-Modus: nur Vorschläge ≥ 90% Konfidenz anwenden
python3 music_enricher.py --auto --confidence 0.90 \ python3 music_enricher.py --auto --confidence 0.90 \
--embed-cover --backup /tmp/backup \ --embed-cover --rename --backup /tmp/backup \
~/Musik ~/Musik
# Mit Claude API (ANTHROPIC_API_KEY setzen) # Album mit YouTube-IDs in Dateinamen (yt-dlp holt Titel + Kapitel automatisch)
export ANTHROPIC_API_KEY=sk-ant-... python3 music_enricher.py --auto --confidence 0.1 --rename --embed-cover \
python3 music_enricher.py --dry-run --album ~/Musik/UnbekanntesAlbum --album ~/Musik/Die_Bergvagabunden_Am_Lagefeuer.audio
``` ```
--- ---
@ -116,30 +131,32 @@ python3 music_enricher.py --dry-run --album ~/Musik/UnbekanntesAlbum
Album-Verzeichnis Album-Verzeichnis
1. AlbumScanner — Dateitypen klassifizieren 1. AlbumScanner — Dateitypen klassifizieren (Audio, Bild, Tracklist, Playlist)
2. HintExtractor — lokal, keine API 2. HintExtractor — lokal, keine API
├─ Verzeichnisname → Artist, Album, Jahr ├─ Verzeichnisname → Artist, Album, Jahr
├─ Dateinamen → Tracknummer, Artist, Titel ├─ Dateinamen → Tracknummer, Artist, Titel (YouTube-ID wird entfernt)
├─ ID3/FLAC-Tags → bestehende Werte ├─ ID3/FLAC-Tags → bestehende Werte
└─ Tracklist .txt → Tracklisten parsen ├─ 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 3. MetadataResolver
├─ AcoustID → MusicBrainz via Fingerprint ├─ AcoustID → MusicBrainz via Fingerprint
├─ Textsuche → MusicBrainz-API ├─ Textsuche → MusicBrainz-API
├─ Discogs → Fallback ├─ Discogs → Fallback
└─ Claude API → Reasoning-Schritt (optional) └─ LLM-Reasoning → Ollama lokal → OpenRouter (DeepSeek V3)
4. CoverHandler — lokal → MusicBrainz → einbetten 4. CoverHandler — lokal (JPG/PNG/WebP) → MusicBrainz → einbetten
5. ReviewStep — interaktiv oder --auto mit Konfidenz 5. ReviewStep — interaktiv oder --auto mit Konfidenz-Schwellwert
6. Executor — Backup → Tags → Cover → Umbenennen → Report 6. Executor — Backup → Tags → Cover → Umbenennen → M3U → Report
``` ```
--- ---
@ -152,20 +169,28 @@ Album-Verzeichnis
| MusicBrainz via Fingerprint | +0.25 | | MusicBrainz via Fingerprint | +0.25 |
| MusicBrainz-Texttreffer (Score/100) | +0.30 × Score | | MusicBrainz-Texttreffer (Score/100) | +0.30 × Score |
| Discogs | +0.15 | | Discogs | +0.15 |
| Claude-Reasoning | +0.10 | | LLM-Reasoning (Ollama/OpenRouter) | +0.10 |
| Lokale Hints (Ordner-/Dateiname) | +0.05 | | Lokale Hints (Ordner-/Dateiname, YouTube) | +0.05 |
--- ---
## Dateinamen-Schema (mit `--rename`) ## Dateinamen-Schema (mit `--rename`)
**Pop/Default** — Leerzeichen als Unterstriche, Teile durch `_-_` getrennt:
``` ```
01 - ABBA - Dancing Queen.mp3 01_-_ABBA_-_Dancing_Queen.mp3
2-07 - Bach - Toccata And Fugue In D Minor BWV 565.flac 2-07_-_Die_Bergvagabunden_-_Hohe_Tannen.flac
``` ```
Bei Single-Disc entfällt die Disc-Nummer. Bei Multi-CD-Alben (Unterordner `CD1/`, `CD2/` etc.) **Klassik** — Performer und Komponist explizit getrennt:
wird die Disc-Nummer automatisch erkannt. ```
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.).
--- ---
@ -176,10 +201,10 @@ Music_Metadata_Enricher/
├── music_enricher.py Haupt-CLI, Pipeline-Orchestrierung ├── music_enricher.py Haupt-CLI, Pipeline-Orchestrierung
├── models.py Dataclasses: AlbumScan, AlbumHints, TrackProposal, … ├── models.py Dataclasses: AlbumScan, AlbumHints, TrackProposal, …
├── scanner.py Dateisystem-Scanner, Typ-Klassifikation ├── scanner.py Dateisystem-Scanner, Typ-Klassifikation
├── hint_extractor.py Dateiname/Tag/Tracklist-Auswertung ├── hint_extractor.py Dateiname/Tag/Tracklist/OCR/YouTube-Auswertung
├── metadata_resolver.py MusicBrainz + Discogs + Claude API ├── metadata_resolver.py MusicBrainz + Discogs + Ollama/OpenRouter LLM
├── cover_handler.py Cover-Art: Suche, Download, Einbettung ├── cover_handler.py Cover-Art: Suche, WebP-Konvertierung, Download, Einbettung
├── executor.py Backup, Tag-Schreiben, Umbenennen, CSV-Report ├── executor.py Backup, Tag-Schreiben, Umbenennen, M3U, CSV-Report
└── test_suite_enricher.py 17 Unit-/Integrationstests └── test_suite_enricher.py 17 Unit-/Integrationstests
``` ```