Vier neue reine Bausteine, jeder mit Tests. Sie beantworten Fragen, die Rippy
bisher geraten oder gar nicht gestellt hat.
1. caps.parse_preset_liste - die Preset-NAMEN, die das HandBrake DIESES Workers
wirklich kennt (`--preset-list`, Format im Worker-Image gemessen). Damit
endet das Raten: die Namen unterscheiden sich je HandBrake-Version, und ein
erfundener Name laesst die Kompression scheitern.
Richtigstellung zum SAVEPOINT v3.16: Dort galt es als unmoeglich, die
Hardware-Preset-Namen auf der Rippy-VM zu ermitteln, weil dort kein
Hardware-Encoder laeuft. Gemessen ist das falsch - die Kategorie `Hardware/`
steht vollstaendig in der Liste (VCN, NVENC, QSV, MF). HandBrake trennt
zwei Fragen: --preset-list nennt alle Presets, --help nur die nutzbaren
Encoder. Zwei Fragen, zwei Quellen.
2. mounts.pfad_map_vorschlag/pfad_map_zeile - der fehlende Anschluss fuer
RIPPY_PATH_MAP. Geraten werden muss dafuer nichts: Rippy hat die Freigabe
selbst eingehaengt und kennt ihre Quelle (//host/share). Mountpunkt plus
Quelle IST das Mapping. NFS gibt bewusst "" - Windows-Schreibweise ist nicht
ableitbar (AGENTS Regel D).
Der Test fand dabei sofort die dokumentierte Windows-Falle: os.path.join
baute `/app/media\rippy` in einen Container-Pfad, das Mapping waere still
wirkungslos geblieben. _mountpoint nutzt jetzt posixpath.
3. presets.empfehlung - "immer das Beste" (Commander-Anforderung) ohne
Punktesystem: fuer jede Lage eine feste Reihenfolge echter Namen, genommen
wird der erste, den der Worker kennt. Hardware nur, wenn die Familie
wirklich gemeldet ist (vce -> Preset heisst VCN, sonst liefe eine AMD-Karte
unter dem Intel-Namen). vaapi und MF werden nie empfohlen: fuer vaapi gibt
es kein Preset, bei MF ist die Nutzbarkeit nicht ablesbar.
4. eta - Restzeit aus dem gemessenen Fortschritt. Messreihe je Phase (Rip und
Kompression haben nichts miteinander zu tun), Stillstand verlaengert die
Schaetzung, und unter zwei Messwerten oder 60 Sekunden Spanne gibt es
ehrlich keine Aussage. Test mit den echten 25.07.-Werten: 1,44 % in 29 min
landet bei "noch ca. 1 Tag 23 h" - genau die Angabe, deren Fehlen den
50-Stunden-Lauf unsichtbar machte.
Dazu: HandBrakes "Invalid preset <Name>" wird uebersetzt. Vorher stand im UI
nur "HandBrake endete mit Code 3" - dass der Preset-NAME das Problem ist, war
daraus nicht zu erraten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Folgefix zum remount-Vorfall 24.07.: mounten() fiel bei einem TOTEN Mount
(os.path.ismount wirft OSError) auf den echten `mount` durch und stapelte auf die
Leiche. Ueber viele Neustarts (via rshared propagiert, ueberlebt Container-Recreate)
wuchs das auf 12 Schichten; die tote oberste blockierte jeden Zugriff (ls-Timeout,
obwohl SMB-445 offen) -> Medien-Mount unbrauchbar.
Fix: _stale_mounts_loesen(ziel) loest per lazy `umount -l` alle Schichten, bevor neu
gemountet wird -> kein Stapeln mehr, Re-Mount idempotent. Ein gesunder Mount wird
weiterhin frueh erkannt (os.path.ismount) und unangetastet gelassen.
Tests (test_mounts_helpers.py): Loesch-Schleife bis leer (monkeypatch) + Verdrahtung.
Ruff gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- jobs.meta (Migration in beiden db.py): Disc-Metadaten wandern in den Job —
Quelle fuer Job-Detail-Popup (GET /jobs/{id}/detail), Ordner-Benennung, NFO.
- medien.py (Worker, mit Tests): Zielordner 'Titel (Jahr)' statt Job-UUID;
movie.nfo/tvshow.nfo (Kodi-Schema, kodi.wiki/view/NFO_files) + poster.jpg
fuer jellyfin/emby/kodi; plex nur Benennung; Kollision -> Job-ID-Suffix.
- notify.py (identisch in API+Worker, mit Tests): Webhook bei Job-Ende —
Discord ({content}, discord.com/developers), Slack ({text},
api.slack.com/messaging/webhooks), ntfy (Rohtext + ?title=, docs.ntfy.sh),
generisches JSON. Vorher war das Setting ein Placebo: nichts sendete je.
POST /notifications/test beweist die Anbindung sofort.
- mounts.py: NT_STATUS-Fehler -> handelbarer Klartext (ACCESS_DENIED ohne
Credentials = Gast-Abfrage verweigert), Timeout-Meldung, mount-Hinweis
bei error(13). Mit Tests.
- tasks.py: Platz-Check per Disc-Groesse (ioctl BLKGETSIZE64) VOR dem Rip;
Arbeitsverzeichnis workDir (unter /app/media, z.B. NAS) statt fix
/app/temp/raw — 4K-UHD-Rohdaten (bis 100 GB) sprengen sonst die VM-Platte;
MakeMKV-Key aus UI-Settings (~/.MakeMKV/settings.conf, Format wie
entrypoint.sh) gilt ab dem naechsten Rip ohne Rebuild.
- caps.py: Werkzeug-Versionen (MakeMKV aus ENV MAKEMKV_VERSION im Image,
makemkvcon hat keinen --version-Schalter lt. usage.txt; HandBrakeCLI
--version lt. handbrake.fr/docs) + Key-Quelle; workers.info-Spalte.
- /browse liefert jetzt auch DATEIEN (Name + Groesse) — der 'leere'
bluray-Ordner war voll, der Browser zeigte nur Unterordner.
- GET /system/info: Versionen, Plattenplatz, Key-/Webhook-Status.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>