2026-04-28 16:17:18 +02:00
# Jellyfin Playlist Generator v9
Rekursiver `.m3u` -Playlist-Generator für Jellyfin-Musikbibliotheken.
**Prinzip:** Du gibst ein Root-Verzeichnis an. Jeder direkte Unterordner gilt als Album und bekommt genau eine Playlist. Tracks werden rekursiv aus allen Unterordnern des Albums gesammelt, nach Unterordner und Dateiname natural-sortiert.
---
## Voraussetzungen
Python 3.10+
```bash
pip install mutagen tqdm tenacity # alle optional, aber empfohlen
```
| Paket | Funktion |
|-------|---------|
| `mutagen` | Tags lesen und schreiben |
| `tqdm` | Fortschrittsbalken |
| `tenacity` | Robusteres Retry bei I/O-Fehlern |
Ohne `mutagen` werden nur Playlists erzeugt; Tags werden weder gelesen noch geschrieben.
---
## Aufruf
```
jellyfin_playlist_generator_v9.py [Optionen] PFAD [PFAD ...]
```
### Minimaler Aufruf
```bash
python3 jellyfin_playlist_generator_v9.py /pfad/zur/Musik
```
### Alle Optionen
| Option | Beschreibung |
|--------|-------------|
| `--dry-run` | Simulationsmodus: nichts schreiben, nichts löschen |
| `--relative-to PFAD` | Playlist-Einträge relativ zu diesem Basispfad |
| `--root-playlist` | Zusätzlich pro Root-Verzeichnis eine Sammel-Playlist erzeugen |
| `--write-tags` | Harmonisierte Tags zurück in die Audiodateien schreiben (erfordert `mutagen` ) |
| `--backup PFAD` | Vor dem Tag-Schreiben Originale in dieses Verzeichnis sichern |
| `--report PFAD` | CSV-Report aller Tracks speichern |
| `--no-tqdm` | Fortschrittsanzeige deaktivieren |
---
## Beispiele
**Dry-Run — was würde passieren?**
```bash
python3 jellyfin_playlist_generator_v9.py --dry-run /mnt/Musik
```
**Playlists mit relativen Pfaden (für portierbare Jellyfin-Bibliothek)**
```bash
python3 jellyfin_playlist_generator_v9.py --relative-to /mnt/Musik /mnt/Musik
```
**Zusätzliche Sammel-Playlist pro Root**
```bash
python3 jellyfin_playlist_generator_v9.py --root-playlist /mnt/Musik
```
Erzeugt neben den Album-Playlists auch `/mnt/Musik/Musik.m3u` mit allen Tracks.
**Tags harmonisieren mit Backup**
```bash
python3 jellyfin_playlist_generator_v9.py --write-tags --backup /mnt/Backup /mnt/Musik
```
**CSV-Report für Qualitätskontrolle**
```bash
python3 jellyfin_playlist_generator_v9.py --report /tmp/report.csv /mnt/Musik
```
---
## Verzeichnisstruktur
```
Musik/ ← Root (wird übergeben)
├── Pink Floyd/ ← Album-Ordner
│ ├── CD1/
│ │ ├── 01 - Shine On.mp3
│ │ └── 02 - Have a Cigar.mp3
│ ├── CD2/
│ │ └── 10 - Comfortably Numb.mp3
│ └── Pink Floyd.m3u ← erzeugte Playlist (alle Tracks aus CD1+CD2)
├── Dave Brubeck Quartet/
│ ├── 01 - Blue Rondo.flac
│ └── Dave Brubeck Quartet.m3u
└── Musik.m3u ← nur mit --root-playlist
```
- Versteckte Ordner (`.` oder `_` als Präfix) werden übersprungen.
- Bestehende `.m3u` /`.m3u8` -Dateien werden vor dem Schreiben gelöscht.
- Ordner ohne Mediendateien werden still übersprungen.
---
## Metadaten-Verarbeitung
Das Skript versucht für jeden Track sinnvolle Werte für `title` , `artist` , `album` , `albumartist` , `tracknumber` , `discnumber` und `date` zu ermitteln.
**Quellen (Priorität: Tag > Dateiname > Ordnername):**
1. **ID3/FLAC/MP4-Tags ** via Mutagen
2. **Dateiname-Parsing ** nach diesen Mustern (spezifischste zuerst):
| Muster | Beispiel | Ergebnis |
|--------|---------|---------|
| `D-TT - Titel` | `2-07 - Finale.mp3` | disc=2, track=7, title=Finale |
| `TT - Artist - Titel` | `07 - Pink Floyd - Shine.mp3` | track=7, artist=Pink Floyd, title=Shine |
| `TT - Titel` | `07 - Shine.mp3` | track=7, title=Shine |
| `Artist - Titel` | `Pink Floyd - Shine.mp3` | artist=Pink Floyd, title=Shine |
3. **Disc-Nummer ** aus Unterordnernamen wie `CD1` , `Disc 2` , `Disk_3`
4. **Album-Name ** aus dem Ordnernamen
**albumartist-Harmonisierung:**
- ≥ 3 verschiedene Artists → `Various Artists`
- 1– 2 Artists → Mehrheits-Artist
- Tracks mit bereits gesetztem `albumartist` -Tag werden nicht überschrieben.
**Konflikte** (z. B. Title im Tag weicht vom Dateinamen ab) werden im CSV-Report markiert.
---
## CSV-Report
Felder: `status` , `path` , `title` , `artist` , `album` , `albumartist` , `duration` , `conflicts` , `notes`
`status` ist `ok` , `changed` oder `conflict` .
```bash
python3 jellyfin_playlist_generator_v9.py --report report.csv /mnt/Musik
```
---
## Unterstützte Formate
**Audio:** `.mp3` `.flac` `.m4a` `.aac` `.ogg` `.opus` `.wav` `.wma` `.aiff` `.ape`
**Video:** `.mp4` `.mkv` `.avi` `.mov` `.wmv` `.flv` `.webm` `.m4v` `.mpeg` `.mpg` `.3gp`
---
## Tests
```bash
python3 test_suite_v9.py
```
27 Tests: Unit-Tests für Parsing/Enrichment und Integrationstests für alle CLI-Optionen.
---
## Zusammenfassung-Output
Am Ende jedes Laufs:
```
========================================
✅ Zusammenfassung:
🗑️ Playlists gelöscht: 209
📁 Root-Verzeichnisse verarbeitet: 1
💿 Album-Verzeichnisse verarbeitet: 209
🎵 Tracks analysiert: 6745
📝 Album-Playlists erstellt: 209
⚠️ Konflikte gefunden: 3476
🔄 Tags geschrieben: 0
❌ Fehler: 0
========================================
```