diff --git a/SAVEPOINT.md b/SAVEPOINT.md index 11d3957..5923fcb 100644 --- a/SAVEPOINT.md +++ b/SAVEPOINT.md @@ -1,6 +1,224 @@ # SAVEPOINT — Rippy -## Aktueller Stand: v4.0-rc10 — makemkvcon ueberlebt Rippy nicht mehr (29.08.2026) +## Aktueller Stand: v4.0-rc11 — der Schalter, den es nicht gibt (30.08.2026) + +> **Ein falscher Kommandozeilen-Schalter kostete einen fertigen 16,5-GB-Rip — +> und HandBrake meldete es als Erfolg.** Dazu vierzehn weitere Funde aus +> demselben Rundgang. 977 Tests gruen. + +### Der Befund + +Spartacus Disc 2, eine Blu-ray mit Kratzern. MakeMKV sichert 1 von 2 Titeln, +die Kompression startet — und ist in derselben Sekunde vorbei: + +``` +13:18:57 Kompression gestartet (1 Datei, Preset 'H.265 VCN 1080p') +13:18:57 Kompression fehlgeschlagen: HandBrake endete mit Code 0 +``` + +Nachgestellt mit genau der Befehlszeile, die Rippy baute: + +``` +unknown option (--audio-codec) +HandBrake has exited. $? = 0 +``` + +**Den Schalter `--audio-codec` gibt es bei HandBrakeCLI nicht** — er heisst +`-E` / `--aencoder`. Und ein unbekannter Schalter ist fuer HandBrake kein +Fehler: Rueckgabewert **0**. Rippy sah nur „Code 0" und keine Datei, riet auf +„Zielordner nicht beschreibbar" — und schickte die Suche in die falsche +Richtung. + +Ein Test hat den Fehler festgeschrieben statt ihn zu finden: +`assert "--audio-codec" in cmd`. Ein Kommandozeilen-Schalter ist eine externe +Schnittstelle (Regel D) — er gehoert am echten Programm gemessen. + +### Die Kompression + +* **`--aencoder` statt `--audio-codec`.** Am mitgelieferten HandBrakeCLI + 1.11.2 gemessen, danach mit einem 5-Sekunden-Encode auf der echten + Roh-Datei gegengeprueft. +* **HandBrakes letzte Worte werden aufgehoben** (12 Zeilen gepuffert, 4 in der + Meldung). Vorher wurde jede Zeile weggeworfen, die kein Fortschritt war — + bei Rueckgabewert 0 blieb damit gar keine Auskunft uebrig. Dazu eine eigene + Erkennung fuer `unknown option (...)`, die VOR allen anderen greift. +* **Ein `ü` im Pfad toetete die Kompression.** HandBrake schreibt zwei + Kodierungen in denselben Strom — denselben Pfad einmal als UTF-8, einmal als + CP850. In CP850 ist `ü` das Byte 0x81, und das ist in cp1252 (was + `text=True` auf einem deutschen Windows waehlt) **undefiniert**: + +``` +UnicodeDecodeError: charmap codec can't decode byte 0x81 in position 785 +``` + + Betroffen war jeder Film mit „Glück", „Tür", „München", „Über", „Grün" — + dazu `ì`, `Å`, `É`, `Ø`. Die Entscheidung liegt jetzt als `HB_LESEN` im + gemeinsamen `rip/handbrake_aufruf.py`, weil `caps.py` HandBrake ebenfalls + aufruft. Bewusst NICHT binaer wie bei makemkvcon: HandBrake trennt seine + Fortschrittszeilen mit CR. + +### Die Rohdaten + +* **`F:\` wurde zu `F:`.** `rohdaten.kandidaten` strich den Schluss-Trenner ab + und verband mit dem Rest weiter. `F:` ohne Trenner ist unter Windows der + AKTUELLE Ordner auf Laufwerk F, nicht dessen Wurzel: + +``` +verbinden("F:", job_id) -> F:1aa41fef-... isdir: False +verbinden("F:\", job_id) -> F:\1aa41fef-... isdir: True +``` + + 16,5 GB Rohschnitt unsichtbar, und der Wiederholen-Dialog bot nur „Neu + rippen" an: Stunden am beschaedigten Datentraeger fuer etwas, das dalag. Die + Falle steht woertlich im Kopf von `pfade.verbinden`. +* **Gesucht wurde unter der heutigen Einstellung, nicht unter der Wahl des + Jobs.** Der Rip-Dialog laesst pro Rip waehlen (seit v3.15); die Wahl steht in + `meta["work_dir"]`. Genau dafuer wurde `rohdaten.py` am 26.07. gebaut — + repariert wurde damals die Kandidatenliste, nicht der Aufrufer. +* **Zwei Speicher fuer dieselben Ordner.** Die Oberflaeche schreibt + `outputDir`/`workDir` in die Datenbank, `betrieb` liest + `storage.medien`/`storage.temp` aus der Konfigurationsdatei — und die + schreibt niemand. An der laufenden Instanz gemessen: + +``` +eingestellt E:\Rippy (beides) +angezeigt C:\Users\TobisPC\Videos\Rippy und ...\_arbeit +``` + + Neue Bruecke `betrieb.mit_einstellungen` — dieselbe Reihenfolge, die der + Worker seit jeher benutzt. + +### Das Laufwerk + +* **Rippy kannte den Grund und behielt ihn fuer sich.** Nach dem Rip mit 29 + Lesefehlern und einem gescheiterten Auswurf beantwortete das Laufwerk nichts + mehr, was mit dem MEDIUM zu tun hat — die Geraete-Auskunft aber schon: + +``` +CreateFileW mit GENERIC_READ -> Win32-Fehler 1 +IOCTL_STORAGE_CHECK_VERIFY2 -> Win32-Fehler 1 +IOCTL_CDROM_DISK_TYPE -> Win32-Fehler 50 +CreateFileW mit Zugriff 0 -> geht +IOCTL_STORAGE_QUERY_PROPERTY -> geht +``` + + Im UI stand eine vollstaendige Laufwerkskarte mit Modell und Seriennummer, + daneben „unknown" — und kein Rip startbar. Commander: *„jetzt erkennt rippy + die disk garnicht mehr (im log steht zwar erkannt, aber ein start des rips + ist nicht möglich)"*. Jetzt gibt es `ZUGRIFFS_GRUENDE` mit gemessenem + Klartext je Fehlernummer, der Grund reist im Laufwerks-Eintrag mit, und die + Wache schreibt ihn einmal je Wechsel ins Protokoll — samt „antwortet + wieder". Auch eine fehlgeschlagene Disc-Erkennung landet dort, statt nur auf + einer Konsole, die niemand sieht. +* **Der Linux-Treiber nannte ein unzugaengliches Laufwerk „empty"**, waehrend + Windows richtig „unknown" sagt. Dieselbe Lage, zwei Antworten. Angeglichen; + der Feld-Paritaetstest deckt das neue Feld mit ab. +* **ctypes ohne Typangaben.** `CreateFileW`, `DeviceIoControl` und + `CloseHandle` hatten weder `restype` noch `argtypes` — ctypes nimmt dann + 32-Bit-`c_int` fuer einen 64-Bit-HANDLE, hin wie zurueck. Die Tuecke: Mit + `restype` aendert sich der Fehlerwert von -1 auf 0xFFFFFFFFFFFFFFFF, die + alte Pruefung haette stillschweigend aufgehoert zu greifen. Am echten + Laufwerk gegengeprueft, Fehlerpfad eingeschlossen. +* **Der teure Vor-Scan, den niemand las.** Bei jeder eingelegten Disc lief ein + `makemkvcon info` mit 120 s Zeitgrenze — auf einer Blu-ray 20 bis 120 + Sekunden „Disc wird gelesen". Commander: *„das erkennen der disk dauert sehr + sehr lange. Das ging mal viel schneller."* Es ging schneller, weil der Zweig + unter Windows NIE lief (`shutil.which`, repariert am 28.08.). Und das + Ergebnis landete allein in `toc["tracks"]`, das niemand liest — der + Rip-Dialog holt seine Liste ueber `/devices/{id}/scan-tracks`, wenn sie + gebraucht wird. + +### Drei Notbremsen + +* **Endlosschleife vor jedem Rip.** `_frei_bytes` suchte den naechsten + vorhandenen Ordner selbst. `os.path.dirname("Q:\\")` gibt sich SELBST + zurueck — an einem freien Laufwerksbuchstaben gemessen, nach drei Runden + festgefahren. Ein Arbeitsverzeichnis auf einer abgezogenen Platte haette den + Job stumm haengen lassen, in `_platz_pruefen`, also VOR dem Rip. + `pfade.naechster_vorhandener` macht es seit V2-1 richtig; es war die ganze + Zeit da. +* **Laufwerks- und UNC-Wurzeln** bleiben in `naechster_vorhandener` jetzt + absolut — dieselbe Falle wie bei den Rohdaten, zweiter Fundort. +* **`rmdir /s /q` aus der Registry.** Das Aufraeum-Skript der Deinstallation + baut seinen Loeschbefehl aus `InstallLocation`, also aus dem `--ziel` beim + Installieren. Waere das eine Laufwerks-Wurzel, loeschte die Deinstallation + das Laufwerk; der noetige rstrip macht den Fall erst scharf. Nicht + beobachtet — aber nicht wiedergutzumachen. + +### Lesefehler heissen jetzt Lesefehler + +MakeMKV sicherte 1 von 2 Titeln, beendete sich mit 0, und Rippy schrieb „Rip +fertig". Dass ein Titel fehlt, stand nur in Zeilen, die niemand liest. Jetzt +gibt es eine Warnung nach dem Rip — auch und gerade dann, wenn er als Erfolg +endet — mit Abhilfe: reinigen, anderes Laufwerk. Und **die MSG-Nummer steht im +Protokoll**: MakeMKVs Texte sind uebersetzt, die Nummern nicht. + +### Zwei Funde aus der Gegenprobe am laufenden Rippy + +Die erste Fassung von rc11 war installiert, als der Commander meldete: *„nun +öffnen sich diverse fenster im hintergrund, gehen ganz kurz auf und dann +wieder zu. Das laufwerk hört auch einfach auf zu lesen."* Beides waren +Altlasten, die erst jetzt sichtbar wurden. + +**Die aufblitzenden Fenster.** Prozesserzeugung 20 Sekunden lang mitgeschnitten: + +``` +14:54:40 timeout.exe timeout 4 ls -d C:\Users\...\d7ee6c06-... +14:54:40 WindowsTerminal.exe +``` + +`rohdaten.pruefen` fragt „gibt es dieses Verzeichnis?" mit `timeout N ls -d`. +Unter Linux ist das genau richtig: `os.path.isdir` kann an einem toten +CIFS-Mount im Kernel haengen (Zustand D, 26.07.2026), ein Kind-PROZESS laesst +sich abbrechen. Unter Windows ist es dreifach falsch — `timeout.exe` gibt es +dort, sie wartet aber nur Sekunden ab und kennt weder `ls` noch `-d`; sie +braucht eine Konsole, und die reisst Windows auf; und ihr Rueckgabewert ist +nie 0, also lautete die Antwort **„weg" fuer jedes Verzeichnis**. Rohdaten +waren unter Windows grundsaetzlich unsichtbar — der zweite, tiefere Grund fuer +„Auf der Platte liegt zu diesem Job nichts (mehr)". Neu: `nativ_nachsehen()`, +und dieselbe Absicherung fuer die zwei gleichartigen Aufrufe in `mounts.py`. + +**Das Laufwerk hoert auf zu lesen.** Aus dem Protokoll: + +``` +12:49:52 bluray-Rip gestartet +12:50:09 [watcher] Laufwerk G: beantwortet keine Medien-Abfragen mehr +12:50:12 MSG 2003 SCSI-Fehler ILLEGAL REQUEST:INVALID FIELD IN CDB +12:50:12 MSG 5010 Das Oeffnen der Disk schlug fehl +12:50:12 makemkvcon endete mit Code 11 +``` + +Der Waechter fragt alle drei Sekunden `device_info` ab — drei `CreateFileW` +plus IOCTLs auf ein Geraet, das waehrenddessen makemkvcon gehoert. +`_auto_prescan` haelt sich seit dem 29.08.2026 an die Regel *„Es gibt keinen +Grund, waehrend eines Rips zu scannen"*; die Laufwerksabfrage tat es nicht. +Jetzt gilt waehrend eines Rips der letzte bekannte Stand — das ist keine +Notluege, denn am Laufwerk aendert sich in der Zeit nichts. + +Sichtbar wurden beide erst durch die neue Protokollzeile aus demselben +Rundgang. Ein Fehler, der sich meldet, sieht aus wie ein neuer. + +### Geprueft, nichts gefunden + +FLAC samt MusicBrainz-Tags mit Umlauten (landen korrekt als UTF-8) · die +makemkvcon-Aufrufe in `schluessel.py` (haben `errors="replace"` bereits) · die +Laufwerksliste in `main.py` (rstrip nur fuer den Anzeigenamen) · die uebrigen +`dirname`-Schleifen (es gab nur die eine) · `unbekanntes_preset` (Wortlaut und +Rueckgabewert 2 gemessen — korrekt). + +### Zwei Tests, die gelogen haben + +* `assert "--audio-codec" in cmd` — schrieb den Fehler fest, statt ihn zu + finden. +* `lambda: {}` als Doppelgaenger fuer + `get_settings(key="ui", bei_fehler_leer=False)` — brach, sobald ein Aufrufer + einen Parameter benutzte, und zeigte dann auf den Code statt auf sich + selbst. Ein Doppelgaenger muss die Schnittstelle abbilden, die er ersetzt, + nicht nur den einen Aufruf, den es gerade gibt. + +--- + +## v4.0-rc10 — makemkvcon ueberlebt Rippy nicht mehr (29.08.2026) > **Ein liegengebliebener `makemkvcon` haelt das Laufwerk fest — jeder spaetere > Rip scheitert dann.** 954 Tests gruen.