Vervollständigt die Informationen über ein Musik-Datei-Verzeichnis, passt die Dateinamen und Metadaten der Dateien entsprechend an.
Find a file
dschlueter cd6c0ae185 Fix crash on vinyl track positions like 'A1', 'B2' from MusicBrainz
MusicBrainz returns vinyl track numbers as 'A1', 'B3' etc. instead of
plain integers. int('A1') raised ValueError crashing the entire album.

metadata_resolver.py: parse vinyl positions with regex before int():
- 'A1' → track 1, disc 1 (side A)
- 'B3' → track 3, disc 1 (side B)
- 'C1' → track 1, disc 2 (side C)
- Non-vinyl: extract first digit group via re.search

hint_extractor.py: guard int(tl_track) in tracklist matching with
try/except + re.search so any non-numeric track position is skipped
gracefully instead of crashing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 09:12:31 +02:00
.gitignore Add project-specific .gitignore entries 2026-04-29 05:44:05 +02:00
BEDIENUNGSANLEITUNG.md Add BEDIENUNGSANLEITUNG.md (German user manual) 2026-04-29 06:52:44 +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 --skip-complete: skip already-enriched albums in batch runs 2026-04-29 09:05:51 +02:00
README.md Update README: Ollama/OpenRouter LLM, OCR, YouTube, WebP, underscore schema 2026-04-29 06:03:39 +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 — bei MusicBrainz-Misses
  • LLM-Reasoning — Ollama (lokal, kostenlos) → OpenRouter (DeepSeek V3) für 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, 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

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

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

# 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          → Fallback
   └─ LLM-Reasoning   → Ollama lokal → OpenRouter (DeepSeek V3)
      │
      ▼
4. CoverHandler        — lokal (JPG/PNG/WebP) → MusicBrainz → 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  17 Unit-/Integrationstests

Tests

python3 test_suite_enricher.py
# 📊 17/17 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