fix(windows): Zweiter Rip startete waehrend der Kompression ins leere Laufwerk

Der Commander meldete einen Rip-Fehlschlag „bei der Komprimierung", obwohl
der Rip laengst durch war:

    makemkvcon endete mit Code 11 — letzte Meldung:
    Das Öffnen der Disk schlug fehl  — keine MKV-Datei entstanden

Auffaellig war, was FEHLTE: kein „Ursache:". Waere der Geraetepfad schuld
gewesen, stuende dort MSG 2024. Bleibt: kein Datentraeger im Laufwerk.

Der Ablauf dahinter:
  1. Rip fertig → Rippy wirft die Disc aus (Standardeinstellung)
  2. Status wird auf `transcoding` gesetzt — ab hier sagte `has_active_job`
     NEIN, das Laufwerk sei frei; es kennt nur pending/running
  3. Die Disc-Wache sieht beim Auswurf einen Statuswechsel → „eingelegt"
  4. Die Vollautomatik startet einen ZWEITEN Rip — auf ein Laufwerk, dessen
     Schublade gerade herausfaehrt

Der zweite Rip lief in ein leeres Laufwerk. Auf dem Bildschirm sah das aus,
als sei die Kompression gescheitert — sie lief ungestoert weiter.

Drei Aenderungen:

* `store.job_offen` — der weitere Riegel (pending/running/transcoding/
  canceling) fuer die Vollautomatik. `has_active_job` bleibt unveraendert:
  Das fragt „haelt gerade jemand das Laufwerk?", und waehrend der Kompression
  tut das niemand — ein Auswurf von Hand bleibt erlaubt.
* `ripping.disc_fehlt` — vor dem makemkvcon-Start nachsehen, ob ueberhaupt
  eine Disc drin liegt. Statt zwei Minuten Warten und Code 11 gibt es einen
  Satz, den man versteht. Ein FEHLGESCHLAGENER Blick verweigert nichts:
  „ich weiss es nicht" darf nie zu „es geht nicht" werden.
* MSG 5010 in KRITISCHE_CODES — MakeMKVs Sammelmeldung sagt fuer sich nichts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-29 20:36:59 +02:00
co-authored by Claude Opus 5
parent f6f0a4ccb6
commit f0f719ca12
6 changed files with 215 additions and 1 deletions
+46
View File
@@ -780,6 +780,48 @@ def write_abcde_config(output_dir: str) -> str:
return tmp.name
def disc_fehlt(device_path: str, zustand=None) -> str:
"""Liegt ueberhaupt eine Disc drin? Klartext-Grund oder "" (alles gut).
## Warum vorher nachgesehen wird (Befund 29.08.2026)
Der Commander bekam:
makemkvcon endete mit Code 11 — letzte Meldung:
Das Öffnen der Disk schlug fehl — keine MKV-Datei entstanden
Auffaellig war, was FEHLTE: kein „Ursache:". Waere der Geraetepfad schuld
gewesen, stuende dort MSG 2024. Bleibt: kein Datentraeger im Laufwerk.
Nach einem fertigen Rip wirft Rippy die Disc aus — ein zweiter Versuch
trifft dann ein leeres Laufwerk, laeuft zwei Minuten in makemkvcon hinein
und meldet einen Satz, aus dem niemand das schliessen kann.
Nachsehen kostet Millisekunden und erspart genau diesen Satz.
⚠️ Ein FEHLGESCHLAGENER Blick ist kein Grund, den Rip zu verweigern. Wer
das Laufwerk gerade nicht lesen kann, weiss nicht, dass es leer ist — und
„ich weiss es nicht" darf nie zu „es geht nicht" werden.
"""
if zustand is None:
try:
from rippy import drives as _schicht
zustand = _schicht.treiber().drive_status
except Exception: # noqa: BLE001
return ""
try:
stand = zustand(device_path)
except Exception: # noqa: BLE001
return ""
if stand == CDS_NO_DISC:
return ("Kein Datentraeger im Laufwerk %s. Nach einem fertigen Rip "
"wirft Rippy die Disc aus — fuer einen neuen Rip muss sie "
"wieder hinein." % device_path)
if stand == CDS_TRAY_OPEN:
return "Die Schublade von %s ist offen." % device_path
return ""
def run_makemkv(device_path: str, output_dir: str, progress_cb=None, titel: str = "all",
log_cb=None) -> dict:
"""Rippt eine DVD/Blu-ray verlustfrei mit makemkvcon; meldet Fortschritt.
@@ -794,6 +836,10 @@ def run_makemkv(device_path: str, output_dir: str, progress_cb=None, titel: str
if not check_makemkv_installed():
return {"status": "error", "error": "makemkvcon ist nicht installiert"}
fehlt = disc_fehlt(device_path)
if fehlt:
return {"status": "error", "error": fehlt}
os.makedirs(output_dir, exist_ok=True)
try:
+67
View File
@@ -519,3 +519,70 @@ def test_handbrake_kommando_mit_sprachauswahl():
assert cmd[cmd.index("--audio-lang-list") + 1] == "deu,jpn"
assert cmd[cmd.index("--subtitle-lang-list") + 1] == "deu"
assert "--first-audio" in cmd and "--all-subtitles" in cmd
# ── Erst nachsehen, dann rippen (Befund 29.08.2026) ─────────────────────
#
# Commander: „makemkvcon endete mit Code 11 — letzte Meldung: Das Öffnen der
# Disk schlug fehl — keine MKV-Datei entstanden"
#
# Auffaellig war, was FEHLTE: kein „Ursache:". Waere der Geraetepfad schuld
# gewesen, stuende dort MSG 2024. Bleibt: kein Datentraeger. Nach einem
# fertigen Rip wirft Rippy die Disc aus — ein zweiter Versuch trifft dann ein
# leeres Laufwerk, laeuft zwei Minuten in makemkvcon hinein und meldet einen
# Satz, aus dem niemand das schliessen kann.
def test_ein_leeres_laufwerk_wird_vorher_erkannt():
import ripping
from rippy.drives.linux import CDS_NO_DISC
grund = ripping.disc_fehlt("G:", zustand=lambda p: CDS_NO_DISC)
assert "Kein Datentraeger" in grund
assert "wirft Rippy die Disc aus" in grund, "der Grund muss erklaert sein"
def test_offene_schublade_auch():
import ripping
from rippy.drives.linux import CDS_TRAY_OPEN
assert "Schublade" in ripping.disc_fehlt("G:", zustand=lambda p: CDS_TRAY_OPEN)
def test_mit_disc_wird_nicht_gemeckert():
import ripping
from rippy.drives.linux import CDS_DISC_OK
assert ripping.disc_fehlt("G:", zustand=lambda p: CDS_DISC_OK) == ""
def test_ein_fehlgeschlagener_blick_verweigert_den_rip_NICHT():
"""„Ich weiss es nicht" darf nie zu „es geht nicht" werden. Wer das
Laufwerk gerade nicht lesen kann, weiss nicht, dass es leer ist."""
import ripping
def wirft(p):
raise OSError(5, "Zugriff verweigert")
assert ripping.disc_fehlt("G:", zustand=wirft) == ""
def test_run_makemkv_sieht_vorher_nach():
"""Waechter: Die Pruefung muss VOR dem Prozessstart stehen, sonst laeuft
man weiterhin zwei Minuten ins Leere."""
import inspect
import ripping
quelle = inspect.getsource(ripping.run_makemkv)
vor_popen = quelle.index("subprocess.Popen")
assert "disc_fehlt(" in quelle[:vor_popen], \
"die Disc-Pruefung gehoert vor den makemkvcon-Start"
def test_die_sammelmeldung_5010_wird_erklaert():
"""5010 ist MakeMKVs „ging nicht" und sagt fuer sich nichts."""
from rippy.rip.makemkv_aufruf import KRITISCHE_CODES
assert 5010 in KRITISCHE_CODES
assert "Disc" in KRITISCHE_CODES[5010]