341 lines
8.4 KiB
Markdown
341 lines
8.4 KiB
Markdown
# Jellyfin Trickplay Generator (Legacy Layout)
|
||
|
||
Dieses Script erzeugt **Jellyfin-kompatible Trickplay-Tiles** im **Legacy-Layout** – also genauso, wie du es in deinem Medienordner beobachtet hast:
|
||
|
||
```
|
||
<VideoDatei>.trickplay/
|
||
640 - 10x10/
|
||
0.jpg
|
||
1.jpg
|
||
...
|
||
```
|
||
|
||
✅ **Keine JSON-Datei** im Trickplay-Ordner (Legacy).
|
||
✅ **Parallelisierbar** (mehrere Medien gleichzeitig) – anders als Jellyfin intern.
|
||
✅ **Optional Hardware-Decode** via ffmpeg (`vaapi`, `qsv`, `cuda`, `d3d11va`, `amf`).
|
||
✅ **Resume/Incremental**: Generiert nur fehlende Auflösungen bzw. nur wenn Settings geändert wurden (per-Width Fingerprint).
|
||
✅ **Schöne Konsole** mit Fortschritt (optional via `rich`).
|
||
|
||
---
|
||
|
||
## Voraussetzungen
|
||
|
||
### Python
|
||
- Windows: `py --version`
|
||
- Linux: `python3 --version`
|
||
|
||
### ffmpeg + ffprobe
|
||
Beide müssen verfügbar sein:
|
||
|
||
```bash
|
||
ffmpeg -version
|
||
ffprobe -version
|
||
```
|
||
|
||
Wenn nicht im PATH, kannst du die Pfade in `settings.ini` setzen.
|
||
|
||
### Python-Pakete
|
||
Pflicht:
|
||
```bash
|
||
pip install pillow
|
||
```
|
||
|
||
Optional (für hübsche Fortschrittsbalken):
|
||
```bash
|
||
pip install rich
|
||
```
|
||
|
||
---
|
||
|
||
## Installation (Windows Beispiel)
|
||
|
||
```powershell
|
||
cd "C:\Users\Thorsten\Documents\Scripte"
|
||
py -m pip install pillow rich
|
||
py .\py_jellyfin_trickplay_generator.py
|
||
```
|
||
|
||
---
|
||
|
||
## Installation (Linux Beispiel)
|
||
|
||
```bash
|
||
cd /pfad/zum/script
|
||
python3 -m pip install --user pillow rich
|
||
python3 ./py_jellyfin_trickplay_generator.py
|
||
```
|
||
|
||
---
|
||
|
||
## Konfiguration: `settings.ini`
|
||
|
||
Beim ersten Start wird automatisch eine `settings.ini` im gleichen Ordner erstellt.
|
||
|
||
Beispiel:
|
||
|
||
```ini
|
||
[input]
|
||
paths =
|
||
L:\TV Serien\FSK 0
|
||
L:\Filme
|
||
recursive = true
|
||
|
||
[general]
|
||
output = alongside
|
||
out_dir =
|
||
workers = 6
|
||
replace = false
|
||
keep_temp = false
|
||
loglevel = error
|
||
jpeg_quality = 90
|
||
|
||
[trickplay]
|
||
interval_ms = 10000
|
||
widths = 320,640
|
||
tile_cols = 10
|
||
tile_rows = 10
|
||
|
||
[ffmpeg]
|
||
ffmpeg =
|
||
ffprobe =
|
||
hw = none
|
||
hw_device =
|
||
```
|
||
|
||
### Erklärung wichtiger Optionen
|
||
|
||
#### `[input]`
|
||
- `paths`: Eine oder mehrere Wurzeln. Multi-line empfohlen.
|
||
- `recursive`: `true` findet Medien rekursiv in Unterordnern.
|
||
|
||
#### `[general]`
|
||
- `workers`: Anzahl paralleler Prozesse (Medien parallel).
|
||
- `replace`:
|
||
- `false`: Incremental/Resume (nur fehlende Widths / nur wenn Fingerprint nicht passt)
|
||
- `true`: Alles neu (löscht vorhandene Trickplay-Daten für die Datei)
|
||
- `output`:
|
||
- `alongside` (Standard): direkt neben der Videodatei als `*.trickplay`
|
||
- `dir`: in einem zentralen `out_dir` (selten sinnvoll für Jellyfin Legacy)
|
||
- `loglevel`: ffmpeg Log-Level (`error`, `warning`, `info`, ...)
|
||
|
||
#### `[trickplay]`
|
||
- `interval_ms`: Abstand zwischen Thumbnails (10000ms = alle 10 Sekunden)
|
||
- `widths`: Zielbreiten, z.B. `640` oder `320,640,720`
|
||
- `tile_cols`, `tile_rows`: Grid der Tile-Spritesheets (z.B. `10x10`)
|
||
|
||
#### `[ffmpeg]`
|
||
- `hw` (Hardware-Decode):
|
||
- `none` (Standard)
|
||
- `vaapi` (Linux Intel/AMD iGPU, /dev/dri/…)
|
||
- `qsv` (Intel QuickSync)
|
||
- `cuda` (NVIDIA)
|
||
- `d3d11va` (Windows: Intel/AMD/NVIDIA – Decode über D3D11)
|
||
- `amf` (AMD – intern ebenfalls d3d11va für Decode genutzt)
|
||
- `hw_device`: z.B. `/dev/dri/renderD128` bei VAAPI
|
||
|
||
---
|
||
|
||
## CLI Nutzung (Overrides)
|
||
|
||
CLI-Argumente überschreiben Werte aus der INI:
|
||
|
||
```bash
|
||
python3 py_jellyfin_trickplay_generator.py --workers 8 --widths 640 --interval-ms 10000 /pfad/zu/Medien
|
||
```
|
||
|
||
Rekursiv:
|
||
```bash
|
||
python3 py_jellyfin_trickplay_generator.py --recursive /pfad/zu/Serien
|
||
```
|
||
|
||
---
|
||
|
||
## Fortschritt / Konsole
|
||
|
||
Wenn `rich` installiert ist, zeigt das Script:
|
||
|
||
- **Overall** (Gesamtfortschritt Dateien)
|
||
- **Worker** pro Prozess (Stage: probe / extract / tile / skip)
|
||
|
||
Wenn `rich` fehlt, gibt es einfache Textausgaben pro Datei.
|
||
|
||
---
|
||
|
||
## Resume / Incremental Build (Marker-Dateien)
|
||
|
||
Damit man erkennt, ob ein Durchlauf sauber fertig wurde und um nur fehlende Dinge zu generieren, werden Marker-Dateien genutzt.
|
||
|
||
### Root (pro Video)
|
||
Im `*.trickplay` Root:
|
||
|
||
- `.inprogress` → Job lief / wurde evtl. unterbrochen
|
||
- `.complete` → Job komplett (für genau diese Job-Settings)
|
||
- `.trickplay.job.json` → Job-Settings + Job-Fingerprint
|
||
|
||
### Pro Width
|
||
In jedem Width-Ordner (z.B. `640 - 10x10/`):
|
||
|
||
- `.inprogress` → diese Width wurde gerade gebaut
|
||
- `.complete` → diese Width ist vollständig
|
||
- `.meta.json` → Width-Settings + Width-Fingerprint
|
||
|
||
**Wichtig:** Der Skip passiert nur, wenn
|
||
- Tiles existieren (`0.jpg` vorhanden),
|
||
- `.complete` existiert,
|
||
- und `.meta.json`-Fingerprint zu den aktuellen Settings passt.
|
||
|
||
So kannst du z.B. später `widths = 320,640,720` einstellen und es wird nur 720 nachgezogen.
|
||
|
||
---
|
||
|
||
## Typische Probleme
|
||
|
||
### `ffmpeg not found in PATH`
|
||
- Windows: PowerShell neu öffnen nachdem ffmpeg installiert wurde
|
||
- oder Pfade in `settings.ini` setzen:
|
||
|
||
```ini
|
||
[ffmpeg]
|
||
ffmpeg = C:\Tools\ffmpeg\bin\ffmpeg.exe
|
||
ffprobe = C:\Tools\ffmpeg\bin\ffprobe.exe
|
||
```
|
||
|
||
### `ModuleNotFoundError: No module named 'PIL'`
|
||
```bash
|
||
pip install pillow
|
||
```
|
||
|
||
### Windows: `python3` öffnet Microsoft Store
|
||
Nutze:
|
||
```powershell
|
||
py script.py
|
||
```
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- Das Script implementiert das beobachtete Jellyfin **Legacy** Trickplay-Layout.
|
||
- Wenn Jellyfin in deiner Installation irgendwann auf ein anderes Layout umstellt (mit JSON/Manifest),
|
||
müsste das Script entsprechend erweitert werden.
|
||
|
||
---
|
||
---
|
||
|
||
## ffmpeg Hardware-Decode (hw) – Details (Windows vs Linux)
|
||
|
||
Wichtig: Das Script nutzt Hardware **nur fürs Decode** (Einlesen/Decodieren des Videos).
|
||
Die Ausgabe ist weiterhin **MJPEG** (CPU), was für Trickplay/Thumbs völlig ok ist.
|
||
|
||
### Überblick: Welche `hw`-Option wo sinnvoll ist
|
||
|
||
- **Windows**
|
||
- `d3d11va` ✅ (empfohlen; Intel/AMD/NVIDIA – Decode über Direct3D 11)
|
||
- `cuda` ✅ (NVIDIA Decode; meist stabil, braucht NVIDIA-Treiber + ffmpeg mit CUDA-Support)
|
||
- `qsv` ✅ (Intel Quick Sync; benötigt Intel iGPU + Treiber; ffmpeg Build muss QSV unterstützen)
|
||
- `amf` ⚠️ (AMD AMF ist in ffmpeg primär Windows-Stack; im Script wird fürs Decode intern ebenfalls `d3d11va` genutzt)
|
||
- `vaapi` ❌ (VAAPI ist Linux/Unix-Stack)
|
||
|
||
- **Linux**
|
||
- `vaapi` ✅ (empfohlen für Intel iGPU & AMD GPUs über Mesa VAAPI)
|
||
- `qsv` ✅ (Intel Quick Sync; je nach Distribution/ffmpeg Build)
|
||
- `cuda` ✅ (NVIDIA; benötigt Treiber + ffmpeg mit CUDA/NVDEC)
|
||
- `d3d11va` ❌ (Windows-only)
|
||
- `amf` ❌/⚠️ (AMD AMF ist i.d.R. nicht der Linux-Standardpfad; auf Linux nimmst du für AMD fast immer `vaapi`)
|
||
|
||
### `hw_device` – wann braucht man das?
|
||
|
||
Im Script wird `hw_device` derzeit **nur für `vaapi`** genutzt.
|
||
|
||
#### VAAPI (Linux): Device angeben
|
||
- Typisch: `hw = vaapi`
|
||
- Device: **Render-Node** unter `/dev/dri/`
|
||
|
||
Meist ist das:
|
||
- `/dev/dri/renderD128` (sehr häufig)
|
||
- oder `/dev/dri/renderD129` (wenn mehrere GPUs vorhanden)
|
||
|
||
**So findest du die Render Nodes:**
|
||
```bash
|
||
ls -l /dev/dri/
|
||
```
|
||
|
||
Beispiel output:
|
||
- `card0`, `card1` (Display devices)
|
||
- `renderD128`, `renderD129` (Render nodes, die wir wollen)
|
||
|
||
**Empfehlung:** immer den `renderD*` Node verwenden, nicht `card*`.
|
||
|
||
In `settings.ini`:
|
||
```ini
|
||
[ffmpeg]
|
||
hw = vaapi
|
||
hw_device = /dev/dri/renderD128
|
||
```
|
||
|
||
#### QSV (Intel Quick Sync): Device meist leer lassen
|
||
Im Script wird QSV aktuell so genutzt:
|
||
- `-hwaccel qsv`
|
||
|
||
In den meisten Fällen brauchst du **kein** `hw_device`.
|
||
Wenn du später tiefer optimieren willst (z.B. spezielles QSV device), müsste man das Script erweitern.
|
||
|
||
In `settings.ini`:
|
||
```ini
|
||
[ffmpeg]
|
||
hw = qsv
|
||
hw_device =
|
||
```
|
||
|
||
#### CUDA (NVIDIA): Device leer lassen
|
||
CUDA/NVDEC benötigt typischerweise kein Device-Argument (Treiber entscheidet).
|
||
|
||
```ini
|
||
[ffmpeg]
|
||
hw = cuda
|
||
hw_device =
|
||
```
|
||
|
||
#### D3D11VA (Windows): Device leer lassen
|
||
Direct3D 11 VA ist ein Windows-API; Device-Auswahl erfolgt automatisch.
|
||
|
||
```ini
|
||
[ffmpeg]
|
||
hw = d3d11va
|
||
hw_device =
|
||
```
|
||
|
||
---
|
||
|
||
## Troubleshooting Hardware-Decode
|
||
|
||
### 1) Erst testen, ob ffmpeg den hwaccel kennt
|
||
```bash
|
||
ffmpeg -hide_banner -hwaccels
|
||
```
|
||
Da sollte z.B. `vaapi`, `qsv`, `cuda`, `d3d11va` auftauchen.
|
||
|
||
### 2) Linux VAAPI: Treiber/Stack
|
||
- Intel: `intel-media-driver` (neuere Gen) oder `i965-va-driver` (älter)
|
||
- AMD: Mesa VAAPI (`mesa-va-drivers`)
|
||
|
||
Test:
|
||
```bash
|
||
vainfo
|
||
```
|
||
Wenn `vainfo` schon Fehler wirft, wird ffmpeg mit `vaapi` auch zicken.
|
||
|
||
### 3) NVIDIA CUDA/NVDEC
|
||
Wenn `ffmpeg -hwaccels` kein `cuda` zeigt, ist dein ffmpeg-Build evtl. ohne CUDA.
|
||
|
||
### 4) Wenn’s instabil ist
|
||
Setze erst mal:
|
||
```ini
|
||
[ffmpeg]
|
||
hw = none
|
||
```
|
||
und prüfe, ob alles stabil durchläuft. Danach wieder mit `hw` testen.
|
||
|
||
### 5) Mehrere GPUs
|
||
- Linux: VAAPI über `renderD128`/`renderD129` zielst du die GPU indirekt an.
|
||
- Windows: D3D11VA/CUDA/QSV nutzen i.d.R. automatisch die passende Hardware; explizite Auswahl wäre möglich, ist aber derzeit im Script nicht vorgesehen. |