fix(windows): Vollstaendiger Rundgang durch die Docker-Reste
Ampel / ampel (push) Successful in 1m20s

Commander: „Bro, du musst alles was rippy jetzt im code hat für Windows
Bauen! Jeden pfad, alles wo die tools drauf zugreifen. Diese Rippy version
MUSS 100% Windows Kompatibel sein. Prüfe bitte den kompletten Quellcode nach
Docker Resten."

Systematisch gesucht statt Fundstelle fuer Fundstelle: feste POSIX-Pfade,
Linux-Programme, POSIX-eigene Aufrufe, `shutil.which`, `posixpath` auf echten
Pfaden, Container-Texte. Sechs echte Fehler dabei.

## 1. `/dev/{name}` in drei Endpunkten — der schwerste

Das UI ruft `/devices/{id}/eject`, `/scan-tracks` und `/tracks` mit der
Kennung aus der Geraeteliste auf, unter Windows also `G`. Gebaut wurde daraus
`/dev/G` — steht in keiner Laufwerksliste. **Auswerfen und „Disc scannen"
antworteten unter Windows IMMER mit 404**, ohne dass irgendwo stand, warum.

Hin- und Rueckweg gehoeren zusammen: Beide Treiber haben jetzt `kennung()`
und `pfad_zu_kennung()`. Wer die Kennung vergibt, loest sie auch auf.

## 2. `os.path.isdir("/app")` — zum zweiten Mal

Nach `caps.py` (heute frueh) auch in `ablauf.py`: Der eigenstaendige
Windows-Rippy hielt sich fuer einen FREMDEN Worker und haette sich selbst
vorgeworfen, Container-Pfade nicht zu erreichen — auf einer Maschine ohne
Container. Die Entscheidung ist jetzt einspritzbar; vorher hing der Test
daran, ob es einen Ordner `/app` gibt.

## 3. `shutil.which` in `schluessel.py`

Ausgerechnet im Modul, das es NUR unter Windows gibt: Es suchte makemkvcon im
PATH, wo unter Windows nie ein Programm aus „Programme" steht. Die
Schluessel-Automatik fuer 4K-UHD lief damit nie an.

## 4. `posixpath.join` auf echten Pfaden

`rohdaten.py` baute `C:\Roh/datei.mkv` — gemischte Trenner, die im UI falsch
aussehen und jeden Vergleich brechen.

## 5. Container-Pfad in einer Nutzermeldung

„Roh-Datei bleibt in /app/temp erhalten" nennt jetzt den echten Ordner. Wer
die Datei retten will, sucht sonst am falschen Ort.

## 6. Container-Pfade als UI-Vorbelegung

Rip-Dialog und `useBetrieb` starteten mit `/app/media`, bis die Antwort da
war. Leer ist ehrlicher: Es behauptet nichts.

## Und HandBrakes „Code 0"

Code 0 heisst ERFOLG. Rippy meldete trotzdem „fehlgeschlagen", weil die Datei
nicht am erwarteten Ort lag: **HandBrake bestimmt den Container aus dem
PRESET, nicht aus der Endung** — ein MP4-Preset schreibt `.mp4` neben das
verlangte `.mkv`. Jetzt erzwingt `--format` den Container passend zur Endung
(an HandBrake 1.11.2 gegengeprueft), und falls doch etwas daneben liegt, wird
es gefunden statt weggeworfen.

## Der Waechter

`test_keine_container_reste.py` prueft mechanisch, dass im Windows-Weg kein
Container-Pfad ohne Begruendung steht. Die Ausnahmen stehen namentlich mit
Grund da (Linux-Zweige, benannte Rueckfaelle) — und ein zweiter Test wirft
jede Ausnahme raus, die niemand mehr braucht.

Ueber den Tokenizer, nicht ueber „faengt mit Anfuehrungszeichen an": Der
erste Anlauf blieb prompt an seinem eigenen `r\"\"\"`-Docstring haengen.

887 Tests gruen, ruff sauber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-29 16:14:10 +02:00
co-authored by Claude Opus 5
parent 1a529f4e75
commit 1b84ec2a45
11 changed files with 384 additions and 23 deletions
+10 -6
View File
@@ -162,11 +162,15 @@ export default function RipTargetModal({ isOpen, initialType, discTitle, deviceI
// auf einem Windows-PC eine Ortsangabe fuer einen Ort, den es nicht gibt.
const betrieb = useBetrieb()
const [targets, setTargets] = useState<TargetConfig[]>([
{ id: '1', name: 'Filme', path: '/app/media/movies', type: 'movies', isActive: true },
{ id: '2', name: 'Serien', path: '/app/media/series', type: 'series', isActive: true },
{ id: '3', name: 'Musik', path: '/app/media/music', type: 'music', isActive: true },
])
/*
* Leer starten statt mit Container-Pfaden (Befund 29.08.2026).
*
* Hier standen `/app/media/movies` & Co. als Anfangswert. Auf einem
* Windows-PC gibt es die nicht — und fuer den Augenblick zwischen Oeffnen
* des Dialogs und der Antwort von /settings stand dort ein Pfad, den es
* nirgends gibt. Ein leerer Wert ist ehrlicher: Er behauptet nichts.
*/
const [targets, setTargets] = useState<TargetConfig[]>([])
const [browsePath, setBrowsePath] = useState<string>('')
const [browseParent, setBrowseParent] = useState<string | null>(null)
const [browseDirs, setBrowseDirs] = useState<BrowseDir[]>([])
@@ -223,7 +227,7 @@ export default function RipTargetModal({ isOpen, initialType, discTitle, deviceI
.split(',').map((t: string) => t.trim().toLowerCase()).filter(Boolean)
setStandardAudio(codes(s.audioSprachen))
setStandardUntertitel(codes(s.untertitelSprachen))
const basis = s.outputDir || betrieb.ablage_vorgabe || '/app/media'
const basis = s.outputDir || betrieb.ablage_vorgabe
setTargets([
{ id: '1', name: 'Filme', path: `${basis}/${s.movieDir || 'movies'}`, type: 'movies', isActive: true },
{ id: '2', name: 'Serien', path: `${basis}/${s.seriesDir || 'series'}`, type: 'series', isActive: true },
+5 -2
View File
@@ -77,8 +77,11 @@ const VORGABE: Betrieb = {
werkzeuge_verwalten: false,
frei_blaettern: false,
},
ablage_vorgabe: '/app/media',
arbeits_vorgabe: '/app/temp',
// Leer statt Container-Pfade: Bis /betrieb geantwortet hat, WISSEN wir den
// Ort nicht. Ein leeres Feld sagt das; „/app/media" behauptet etwas, das
// auf einem Windows-PC falsch ist (Befund 29.08.2026).
ablage_vorgabe: '',
arbeits_vorgabe: '',
hilfe_befehl: 'docker compose -p rippy ps',
geladen: false,
}