Vervollständigt die Informationen über ein Musik-Datei-Verzeichnis, passt die Dateinamen und Metadaten der Dateien entsprechend an.
Find a file
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
.gitignore Add project-specific .gitignore entries 2026-04-29 05:44:05 +02:00
BEDIENUNGSANLEITUNG.md Add --except PATTERN option and update documentation 2026-04-29 11:38:52 +02:00
cover_handler.py Add 4 new cover/tracklist sources: MB back cover, iTunes, Last.fm, Discogs tracklist 2026-04-29 08:55:17 +02:00
executor.py Improve _is_classical(): genre keywords + composer list as primary signals 2026-04-29 08:44:34 +02:00
hint_extractor.py Fix crash on vinyl track positions like 'A1', 'B2' from MusicBrainz 2026-04-29 09:12:31 +02:00
metadata_resolver.py Fix crash on vinyl track positions like 'A1', 'B2' from MusicBrainz 2026-04-29 09:12:31 +02:00
models.py Add YouTube ID detection and metadata lookup via yt-dlp 2026-04-29 05:42:03 +02:00
music_enricher.py Add --except PATTERN option and update documentation 2026-04-29 11:38:52 +02:00
README.md Add --except PATTERN option and update documentation 2026-04-29 11:38:52 +02:00
scanner.py Recursive album discovery + Jellyfin Playlist Generator integration 2026-04-29 07:07:55 +02:00
test_suite_enricher.py Add 4 new cover/tracklist sources: MB back cover, iTunes, Last.fm, Discogs tracklist 2026-04-29 08:55:17 +02:00

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

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