feat(bausteine): Preset-Liste, Pfad-Vorschlag und Restzeit - alles gemessen
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>
This commit is contained in:
@@ -106,6 +106,58 @@ def leite_backends_ab(hb_encoder) -> list:
|
||||
return gefunden
|
||||
|
||||
|
||||
def parse_preset_liste(text: str) -> list:
|
||||
"""Preset-NAMEN, die DIESES HandBrake wirklich kennt.
|
||||
|
||||
Quelle: `HandBrakeCLI --preset-list`, am 26.07.2026 im Worker-Image
|
||||
gemessen (HandBrake 1.6.1) — AGENTS Regel D, nicht aus dem Kopf:
|
||||
|
||||
General/
|
||||
Very Fast 2160p60 4K AV1
|
||||
AV1 video (up to 2160p60) and AAC stereo audio, in an MP4
|
||||
container.
|
||||
Hardware/
|
||||
H.265 VCN 2160p 4K
|
||||
|
||||
Die Struktur ist die Einrückung: Kategorien ohne Einrückung (mit „/" am
|
||||
Ende), Preset-Namen mit GENAU vier Leerzeichen, Beschreibungen mit acht.
|
||||
HandBrakes Logzeilen („[10:26:05] qsv: not available on this system") und
|
||||
Meldungen wie „Cannot load libnvidia-encode.so.1" haben keine Einrückung
|
||||
und fallen damit von selbst weg.
|
||||
|
||||
⚠️ Wichtige Richtigstellung zum SAVEPOINT v3.16: Dort steht, die Namen der
|
||||
HARDWARE-Presets seien auf der Rippy-VM „nicht ermittelbar", weil deren
|
||||
HandBrake keinen Hardware-Encoder hat. Gemessen ist das falsch — die
|
||||
Kategorie `Hardware/` steht vollständig in der Liste (VCN, NVENC, QSV, MF).
|
||||
HandBrake trennt beides: `--preset-list` nennt alle mitgelieferten Presets,
|
||||
`--help` nur die Encoder, die diese Maschine wirklich benutzen kann. Für
|
||||
„welches Preset gibt es" ist die Preset-Liste die Quelle, für „läuft das
|
||||
hier" die Encoder-Liste. Deshalb werden beide gemeldet.
|
||||
"""
|
||||
presets = []
|
||||
for zeile in (text or "").splitlines():
|
||||
if not zeile.strip():
|
||||
continue
|
||||
einrueckung = len(zeile) - len(zeile.lstrip(" "))
|
||||
if einrueckung == 4:
|
||||
presets.append(zeile.strip())
|
||||
return presets
|
||||
|
||||
|
||||
def hole_handbrake_presets() -> list:
|
||||
"""`HandBrakeCLI --preset-list` einmal abrufen (leer, wenn nicht installiert)."""
|
||||
if not shutil.which("HandBrakeCLI"):
|
||||
return []
|
||||
try:
|
||||
aus = subprocess.run(
|
||||
["HandBrakeCLI", "--preset-list"],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
return parse_preset_liste((aus.stdout or "") + (aus.stderr or ""))
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return []
|
||||
|
||||
|
||||
def beste_simd(flags_text: str) -> str:
|
||||
"""Höchste Vektor-Befehlsstufe der CPU — entscheidend fürs Software-Encodieren.
|
||||
|
||||
@@ -285,6 +337,14 @@ def werkzeug_versionen() -> dict:
|
||||
# Die ungefilterte Auskunft von HandBrake — damit im UI nachprüfbar ist,
|
||||
# woher die Backend-Liste kommt.
|
||||
info["handbrake_encoder"] = ",".join(hb_encoder)
|
||||
# Die Preset-NAMEN dieses HandBrake. Damit hört das Raten auf: Das UI bietet
|
||||
# genau an, was der jeweilige Worker kennt — die Namen unterscheiden sich
|
||||
# zwischen HandBrake-Versionen, und ein erfundener Name lässt die Kompression
|
||||
# scheitern (Commander-Anforderung „immer das Beste auswählen" braucht eine
|
||||
# echte Liste, nicht eine geratene).
|
||||
presets = hole_handbrake_presets()
|
||||
if presets:
|
||||
info["presets"] = presets
|
||||
if shutil.which("makemkvcon"):
|
||||
info["makemkv"] = os.getenv("MAKEMKV_VERSION") or "installiert"
|
||||
if shutil.which("HandBrakeCLI"):
|
||||
|
||||
Reference in New Issue
Block a user