From 76b4286ad3bc77c7de97604e2af29e694415cf8f Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 24 Jul 2026 15:29:56 +0200 Subject: [PATCH] Windows-Worker: Pfad-Mapping fuer echte Transcodes + leere-Titel-Meldung + E2E-Beweis dokumentiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pfad_lokal (tasks.py, mit Tests): RIPPY_PATH_MAP uebersetzt Container-Pfade (/app/temp, /app/media) auf Netzlaufwerke des nativen Workers — ohne Mapping unveraendert (Docker-Worker). - Rip-Dialog: 'done' mit 0 Titeln bekommt Klartext (Disc vermutlich nicht entschluesselbar) statt leerer Tabelle. - SAVEPOINT: E2E-Beweis des nativen Windows-Workers dokumentiert (test-windows-nativ online, HandBrake 1.9.2, echte LAN-IP). Co-Authored-By: Claude Fable 5 --- SAVEPOINT.md | 11 +++++++-- docker/ui/src/components/RipTargetModal.tsx | 8 ++++++- docker/worker/tasks.py | 26 +++++++++++++++++++++ docker/worker/test_medien.py | 10 ++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/SAVEPOINT.md b/SAVEPOINT.md index bfba13c..f2eec92 100644 --- a/SAVEPOINT.md +++ b/SAVEPOINT.md @@ -17,8 +17,15 @@ GitHub-Release (URL verifiziert), start-worker.bat (celery -Q transcode --pool=solo), optional -Autostart (schtasks onlogon). tasks.py lädt auf Windows ohne fcntl (Import-Guard); rip_disc ist dort hart verriegelt. - **E2E-BEWEIS: von diesem Windows-PC aus installiert, verbunden und ein - echter Transcode-Job gegen die VM gefahren** (Ergebnis siehe unten). + Für echte Transcodes übersetzt RIPPY_PATH_MAP die Container-Pfade aufs + Netzlaufwerk (pfad_lokal, mit Tests) — Voraussetzung bleibt eine + Freigabe der Rippy-Ablage (derselbe offene Infra-Punkt wie beim + Linux-Remote-Worker/AI-Box). + **E2E-BEWEIS (24.07., Commander-PC):** Installer in einem Rutsch + durchgelaufen (venv, Abhängigkeiten, HandBrakeCLI 1.9.2), Worker + gestartet und in Rippy erschienen: + `test-windows-nativ | online: True | HandBrake: 1.9.2 | IP: 192.168.178.98` + — echte LAN-IP, Celery-Ping grün. Testeintrag danach wieder entfernt. - **Anleitungs-Tab** im UI: kompletter Selbsterklärer (Disc-Weg, Serien, NAS, Media-Server, Benachrichtigungen, Key, Worker, Downloads, FAQ). - Design 2.0 kommt bewusst in eine FRISCHE Session (Commander-Entscheid) — diff --git a/docker/ui/src/components/RipTargetModal.tsx b/docker/ui/src/components/RipTargetModal.tsx index b36a1f1..f26626b 100644 --- a/docker/ui/src/components/RipTargetModal.tsx +++ b/docker/ui/src/components/RipTargetModal.tsx @@ -276,7 +276,13 @@ export default function RipTargetModal({ isOpen, initialType, discTitle, deviceI {scanStatus === 'error' && (

{scanFehler}

)} - {scanStatus === 'done' && ( + {scanStatus === 'done' && titelListe.length === 0 && ( +

+ Keine Titel lesbar — vermutlich kann diese Disc nicht entschlüsselt + werden (Details stehen nach einem Rip-Versuch im Job-Fehler). +

+ )} + {scanStatus === 'done' && titelListe.length > 0 && ( <>
{titelListe.map(t => ( diff --git a/docker/worker/tasks.py b/docker/worker/tasks.py index 011acc2..8842de7 100644 --- a/docker/worker/tasks.py +++ b/docker/worker/tasks.py @@ -46,6 +46,29 @@ from ripping import ( API_URL = os.getenv("API_URL", "http://api:8000") + +def pfad_lokal(pfad: str, mapping: str = None) -> str: + """Übersetzt Rippy-Container-Pfade für native Worker (pure Funktion). + + Der native Windows-Worker sieht /app/temp und /app/media nicht — er + mountet Rippys Freigabe als Netzlaufwerk und setzt RIPPY_PATH_MAP, + z. B. "/app/media=Z:\\media;/app/temp=Y:\\temp". Ohne Mapping (Docker- + Worker: identische Mounts) kommt der Pfad unverändert zurück. + """ + mapping = mapping if mapping is not None else os.getenv("RIPPY_PATH_MAP", "") + if not pfad or not mapping: + return pfad + for paar in mapping.split(";"): + if "=" not in paar: + continue + quelle, ziel = paar.split("=", 1) + if quelle and pfad.startswith(quelle): + rest = pfad[len(quelle):] + if "\\" in ziel: + rest = rest.replace("/", "\\") + return ziel + rest + return pfad + RAW_DIR = os.getenv("RAW_DIR", "/app/temp/raw") MEDIA_ROOT = "/app/media" @@ -453,6 +476,9 @@ def transcode_files(self, job_id: str, raw_dir: str, final_dir: str): Über POST /jobs/{id}/retry-transcode jederzeit neu anstoßbar. """ db.init_db() + # Native Worker (Windows) übersetzen Container-Pfade aufs Netzlaufwerk + raw_dir = pfad_lokal(raw_dir) + final_dir = pfad_lokal(final_dir) quellen = sorted(glob.glob(os.path.join(raw_dir, "*.mkv"))) if not quellen: ergebnis = {"status": "error", "error": f"Keine Roh-MKVs in {raw_dir} gefunden"} diff --git a/docker/worker/test_medien.py b/docker/worker/test_medien.py index 638fa7f..062b8c1 100644 --- a/docker/worker/test_medien.py +++ b/docker/worker/test_medien.py @@ -102,3 +102,13 @@ def test_matche_episoden_ohne_treffer_gibt_none(): dateien = [600] # 10 min passt auf keine 24-min-Episode episoden = [(1, 1440), (2, 1440)] assert matche_episoden(dateien, episoden) is None + + +def test_pfad_lokal_uebersetzt_fuer_windows_worker(): + from tasks import pfad_lokal + + mapping = "/app/media=Z:\\media;/app/temp=Y:\\temp" + assert pfad_lokal("/app/temp/raw/abc", mapping) == "Y:\\temp\\raw\\abc" + assert pfad_lokal("/app/media/movies/Film (2020)", mapping) == "Z:\\media\\movies\\Film (2020)" + assert pfad_lokal("/woanders/x", mapping) == "/woanders/x" + assert pfad_lokal("/app/temp/raw/abc", "") == "/app/temp/raw/abc"