diff --git a/AGENTS.md b/AGENTS.md index efb0dbc..2a8406f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,6 +62,8 @@ Bibliotheks-APIs: `--help`/Doku prüfen und die Fundstelle im Commit nennen. echte Benachrichtigungen, SMB-Klartext-Fehler, UHD-Arbeitsverzeichnis, MakeMKV-Key via UI, Job-Detail-Popup, Toast-Feedback, Ampel-Blocker behoben - ✅ **Etappe 17 (v3.10):** 4K-UHD-Disc-Schlüssel — persistentes - MakeMKV-Datenverzeichnis + `KEYDB.cfg` im UI (der Nachweis mit einer - echten Schlüssel-Datei steht noch aus) + MakeMKV-Datenverzeichnis + `KEYDB.cfg` im UI +- ✅ **Etappe 18 (v3.11):** 4K-UHD gelöst — `makemkvcon` holt Schlüssel + unter Linux nie, unter Windows schon; Schlüsselspeicher übernehmbar. + Akira-UHD geht auf der VM auf (`TCOUNT:5`, bewiesen) - 📝 **Details immer in SAVEPOINT.md** — diese Sektion nennt nur die Etappe diff --git a/KONZEPT.md b/KONZEPT.md index ae77310..cc38df6 100644 --- a/KONZEPT.md +++ b/KONZEPT.md @@ -127,7 +127,7 @@ Ein modular aufgebautes System, das bei Disc-Einwurf automatisch den Typ erkennt | Risiko | Status | Behandlung | |--------|--------|------------| | MakeMKV-Beta-Key-Management | Gelöst | Key-Erneuerung als Cron-Job; DMCA-Ausnahme in DE | -| **Disc-Schlüssel für 4K-UHD (AACS 2.0)** | **Offen — durch Rippy nicht lösbar** | Am 25.07.2026 auf der VM gemessen: MakeMKV holt für unbekannte UHD-Discs keinen Schlüssel mehr (kein Netz-Versuch im Log, keine `hkd_*.bin` im `_private_data.tar`), die dokumentierten Schlüssel-Server sind weltweit tot. Rippy stellt NUR ein persistentes Datenverzeichnis für eine vom Nutzer selbst mitgebrachte `KEYDB.cfg` bereit und gibt die AACS-Dumps heraus — es liefert, lädt und verteilt keine Schlüssel. Siehe §10 (25.07.2026) | +| **Disc-Schlüssel für 4K-UHD (AACS 2.0)** | **Gelöst mit Handgriff** | Am 25.07.2026 auf beiden Maschinen gemessen: `makemkvcon` unter **Linux** ruft Disc-Schlüssel nie ab (kein einziger Verbindungsversuch, mit leerem wie gefülltem Speicher, mit und ohne `--noscan`, `dev:` wie `disc:`), die **Windows**-Version tut es (Meldung 3338). Rippy stellt ein persistentes Datenverzeichnis bereit und nimmt den Schlüsselspeicher `_private_data.tar` einer Windows-Installation sowie ersatzweise eine `KEYDB.cfg` entgegen; damit ging Akira UHD auf der VM auf. Rippy liefert, lädt und verteilt KEINE Schlüssel. Siehe §10 (25.07.2026) | | LXC-Device-Node-Änderungen | Gelöst | udev-Resolver (UUID/Serial) | | Pending-Queue / State-Manager | Gelöst | Redis mit AOF-Persistence | | Hybrid-Discs | Offen | MVP erkennt nur Standard; als "Kann" notiert | @@ -188,11 +188,13 @@ Ein modular aufgebautes System, das bei Disc-Einwurf automatisch den Typ erkennt unverändert; ergänzt wird nur ein **persistentes MakeMKV-Datenverzeichnis** (`MAKEMKV_DATA_HOST`, im Worker `/root/.MakeMKV`, in der API `/app/makemkv-data`) samt Bedienung im UI. Begründung: Am 25.07.2026 auf - der VM nachgemessen — MakeMKV versucht bei einer unbekannten UHD-Disc gar - keinen Online-Abruf mehr, und die früher genutzten Schlüssel-Server sind - weltweit tot; der einzige heute funktionierende Weg ist eine `KEYDB.cfg` - im Datenverzeichnis. **Rippy liefert und verteilt KEINE Disc-Schlüssel und - lädt auch keine herunter** — es hält nur den Platz für eine Datei bereit, + BEIDEN Maschinen nachgemessen — `makemkvcon` unter Linux ruft Disc-Schlüssel + nie ab, die Windows-Version tut es. (Erste Fassung dieses Eintrags behauptete, + MakeMKVs Schlüssel-Kanal sei abgeschaltet; das war falsch und wurde am selben + Tag richtiggestellt.) Rippy nimmt deshalb den Schlüsselspeicher + `_private_data.tar` einer MakeMKV-Installation entgegen und ersatzweise eine + `KEYDB.cfg`. **Rippy liefert und verteilt KEINE Disc-Schlüssel und + lädt auch keine herunter** — es hält nur den Platz für Dateien bereit, die der Nutzer selbst mitbringt, zeigt ehrlich an, was dort liegt, und gibt die AACS-Dumps heraus, die MakeMKV ohnehin selbst schreibt. Das ist genau die Grenze, die `docker/api/makemkv_key.py` in Zeile 14 zieht: die diff --git a/README.md b/README.md index 874fc03..0dda9a0 100644 --- a/README.md +++ b/README.md @@ -78,18 +78,26 @@ NICHT als emuliertes CD-ROM (`media=cdrom`), das kann keine SCSI-Kommandos. (MakeMKV-Forum: „Ultimate UHD Drives Flashing Guide") **und** einen passenden Disc-Schlüssel. Normale BD/DVD gehen mit jedem Laufwerk und ohne Schlüssel-Datei. - **Der Schlüssel ist heute die eigentliche Hürde.** Am 25.07.2026 auf - der Rippy-VM gemessen (Akira UHD, MKB v76, Pressung Dezember 2020): - Laufwerk und MakeMKV waren in Ordnung — „Using LibreDrive mode - (v06.3)", die Disc wurde gelesen — und trotzdem kam „The volume key is - unknown for this disc". MakeMKV versucht dabei **gar nicht mehr**, - online einen Schlüssel zu holen, und die früher genutzten - Schlüssel-Server (`hkdata.fairuse.org`, `hkdata.crabdance.com`) lösen - weltweit nicht mehr auf. Ein MakeMKV-Update ändert daran nichts. - Der einzige Weg, der heute funktioniert, ist eine Datei **`KEYDB.cfg`** - (GROSS geschrieben — Linux unterscheidet Groß- und Kleinschreibung) im - MakeMKV-Datenverzeichnis. Die legst du unter **Einstellungen → System** - ab (siehe unten). + **Der Schlüssel ist heute die eigentliche Hürde — und zwar aus einem + überraschenden Grund.** Am 25.07.2026 auf beiden Maschinen gemessen + (Akira UHD, MKB v76, Pressung Dezember 2020): Laufwerk und MakeMKV + waren in Ordnung — „Using LibreDrive mode (v06.3)", die Disc wurde + gelesen — und trotzdem kam „The volume key is unknown for this disc". + Die Ursache: + **`makemkvcon` unter Linux holt Disc-Schlüssel nie aus dem Netz. Die + Windows-Version tut es.** + Gemessen: Linux baute in keinem einzigen Lauf eine Verbindung nach + draußen auf — geprüft mit leerem und mit gefülltem Schlüsselspeicher, + mit und ohne `--noscan`, mit `dev:` und `disc:`, und mit erzwungener + frischer Prüfung. Dieselbe Disc am selben Laufwerk unter Windows: „Lade + aktuelle HK …", Verbindung zum Schlüssel-Server, Disc geht auf. + Ein MakeMKV-Update ändert daran nichts, und es ist kein Fehler in + Rippy. + **Der Weg drumherum:** MakeMKV einmal auf einem Windows-PC die Disc + öffnen lassen und die dabei gefüllte Datei `_private_data.tar` bei + Rippy unter **Einstellungen → System** hochladen (siehe unten). Für + Pressungen, die auch MakeMKV nicht kennt, bleibt die **`KEYDB.cfg`** + als Notnagel. ⚠️ **Rippy liefert keine Schlüssel mit, lädt keine herunter und verteilt keine.** Rippy stellt nur den Platz für eine Datei bereit, die du selbst mitbringst, und zeigt dir ehrlich an, was dort liegt. @@ -131,26 +139,35 @@ MakeMKV-Beta-Key (wechselt ~monatlich, Forum-Thread t=1053) wird hier im UI eingetragen und gilt ab dem **nächsten Rip** — ohne Rebuild, ohne Neustart; er schlägt den Key aus der `.env`. -**Disc-Schlüssel (`KEYDB.cfg`)** — im selben Tab, nur für 4K-UHD nötig: +**Disc-Schlüssel für 4K-UHD** — im selben Tab, nur für UHD nötig. Der +Hauptweg zuerst: -- **Status**: Rippy zeigt, ob eine `KEYDB.cfg` im MakeMKV-Datenverzeichnis - liegt, mit Pfad, Größe, Anzahl der Disc-Einträge und Änderungsdatum. -- **Hochladen**: Knopf „KEYDB.cfg hochladen", dann deine eigene Datei im - Datei-Dialog auswählen — mehr ist nicht zu tun. Rippy prüft den Inhalt - auf Plausibilität und lehnt Unsinn (leere Datei, versehentlich geladene - HTML-Fehlerseite) mit einer deutschen Klartext-Meldung ab, statt ihn - stillschweigend zu speichern. -- **Entfernen**: ein Knopf, die Datei ist wieder weg. +- **Schlüsselspeicher (`_private_data.tar`)**: Rippy zeigt, **wie viele + Disc-Schlüssel** dieser Worker kennt. Steht dort 0, scheitert jede + unbekannte UHD-Disc. + **So füllst du ihn:** MakeMKV auf einem Windows-PC installieren + (gleicher Beta-Key), Laufwerk anstecken, Disc einmal öffnen — dabei lädt + MakeMKV die Schlüssel nach. Dann in MakeMKV unter *Preferences → + General* das „MakeMKV data directory" nachschlagen und die Datei + `_private_data.tar` daraus hier hochladen. Wirkt ab dem nächsten Rip; + für neue Discs gelegentlich wiederholen. + Rippy prüft die Datei und lehnt sie ab, wenn kein einziger Schlüssel + drinsteckt — sonst ändert sich nichts und niemand versteht, warum. +- **`KEYDB.cfg`** (Notnagel): nur nötig, wenn eine Pressung auch mit + gefülltem Speicher nicht aufgeht, MakeMKV sie also selbst nicht kennt. + Hochladen, Status und Entfernen genau wie oben. - **AACS-Dumps herunterladen**: MakeMKV legt bei jeder unbekannten Disc selbst einen Dump ab. Genau den braucht man, wenn man im MakeMKV-Forum um den Schlüssel für eine neue Pressung bittet — hier holst du ihn dir aus dem Container, ohne SSH. -Der Beta-Key ist die **Lizenz für die Software**; die `KEYDB.cfg` sind -**Disc-Schlüssel** — zwei völlig verschiedene Dinge. **Rippy liefert und -lädt keine Disc-Schlüssel**, es hält nur ein persistentes Verzeichnis -dafür bereit (`MAKEMKV_DATA_HOST`, siehe Tabelle unten) — rebuild-fest, -damit deine Datei einen `docker compose build` überlebt. +Der Beta-Key ist die **Lizenz für die Software**, der Schlüsselspeicher +und die `KEYDB.cfg` sind **Disc-Schlüssel** — zwei völlig verschiedene +Dinge. **Rippy liefert und lädt keine Disc-Schlüssel**, es hält nur ein +persistentes Verzeichnis dafür bereit (`MAKEMKV_DATA_HOST`, siehe Tabelle +unten) — rebuild-fest, damit deine Dateien einen +`docker compose build` überleben. Der Schlüsselspeicher ist der +Zwischenspeicher **deiner eigenen** MakeMKV-Installation. **Updates:** „Auf Updates prüfen" vergleicht mit makemkv.com und den offiziellen HandBrake-Releases (12 h gecacht). MakeMKV-Update ohne @@ -158,10 +175,11 @@ Code-Änderung: `MAKEMKV_VERSION=x.y.z` in die `.env`, dann `docker compose build worker && docker compose up -d worker`. ⚠️ **Richtigstellung (25.07.2026):** Hier stand früher, neue MakeMKV- Versionen brächten „auch die neueste Disc-Schlüssel-Datenbank mit". Das -ist widerlegt — auf der VM nachgemessen: MakeMKV holt für eine unbekannte -UHD-Disc keinen Schlüssel mehr, weder mitgeliefert noch aus dem Netz. Ein -Update lohnt für Programmfehler und neue Laufwerke, hilft aber NICHT -gegen „The volume key is unknown". Dafür brauchst du die `KEYDB.cfg`. +ist widerlegt — MakeMKV liefert überhaupt keine Disc-Schlüssel mit, es +holt sie zur Laufzeit. Und die Linux-Version holt sie nie. Ein Update +lohnt für Programmfehler und neue Laufwerke, hilft aber NICHT gegen „The +volume key is unknown". Dafür brauchst du den Schlüsselspeicher (siehe +oben). HandBrake kommt im Docker-Worker bewusst aus Debian (stabil, hinkt der offiziellen Version hinterher); der native Windows-Worker nutzt die aktuelle Version direkt. @@ -196,7 +214,7 @@ bleibt All-in-one. | `THETVDB_API_KEY` | optional | Serien-Fallback | | `MAKEMKV_APP_KEY` | optional | MakeMKV-Beta-Key (Forum); DVDs gehen ohne — bequemer: im UI unter Einstellungen → System pflegen | | `MAKEMKV_URL_BASE` | optional | alternative Download-Quelle für den Image-Build | -| `MAKEMKV_DATA_HOST` | optional | Host-Verzeichnis für MakeMKVs Daten (Default `/srv/rippy/makemkv`) — hier liegen deine `KEYDB.cfg` und die AACS-Dumps; persistent, überlebt jeden Rebuild | +| `MAKEMKV_DATA_HOST` | optional | Host-Verzeichnis für MakeMKVs Daten (Default `/srv/rippy/makemkv`) — hier liegen dein Schlüsselspeicher `_private_data.tar`, eine etwaige `KEYDB.cfg` und die AACS-Dumps; persistent, überlebt jeden Rebuild | | `OPTICAL_SR` | je Host | Host-Pfad des CD-ROM-Knotens (Default `/dev/sr0`) — siehe „Laufwerk anpassen" | | `OPTICAL_SG` | je Host | Host-Pfad des sg-Knotens des Laufwerks (Default `/dev/sg1`; oft `/dev/sg0`) | | `POSTGRES_PASSWORD` | optional | DB-Passwort (Default `rippy`) — für exponierte Umgebungen ein starkes Passwort setzen | @@ -228,8 +246,9 @@ Voraussetzungen auf dem Ziel-Host: 4. MakeMKV-Datenverzeichnis anlegen: `mkdir -p /srv/rippy/makemkv` (oder eigenen Pfad über `MAKEMKV_DATA_HOST` in der `.env`). Dort liegen MakeMKVs Programmzustand, die AACS-Dumps und — falls du 4K-UHD rippst — - deine eigene `KEYDB.cfg`. Das Verzeichnis gehört dem Host, damit ein - `docker compose build` deine Datei nicht wegwirft. + dein Schlüsselspeicher (`_private_data.tar`) sowie eine etwaige + `KEYDB.cfg`. Das Verzeichnis gehört dem Host, damit ein + `docker compose build` deine Dateien nicht wegwirft. Dann wie im Schnellstart: klonen, `.env` füllen, `docker compose up -d --build`, `http://` öffnen — der Einrichtungs-Assistent führt durch diff --git a/ROADMAP.md b/ROADMAP.md index 49ec459..5e75699 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -430,6 +430,13 @@ lösen weltweit nicht mehr auf. **Fazit: Ein MakeMKV-Update löst das nicht** (das behauptete v3.3 — dort richtiggestellt). Der einzige heute funktionierende Weg ist eine `KEYDB.cfg` im MakeMKV-Datenverzeichnis. +> ⚠️ **Nachtrag am selben Tag (siehe Etappe 18): Die letzte Folgerung war +> falsch.** Die beiden toten Hostnamen stammen aus alten Forumsbeiträgen und +> werden von MakeMKV längst nicht mehr benutzt — der Dienst lebt. Richtig +> ist: `makemkvcon` unter **Linux** fragt nie nach Schlüsseln, die +> **Windows**-Version schon. Alles hier Gebaute bleibt richtig und nötig, +> nur die `KEYDB.cfg` ist nicht der Haupt-, sondern der Ersatzweg. + **Gebaut:** - [x] **Persistentes Datenverzeichnis**: `${MAKEMKV_DATA_HOST:-/srv/rippy/makemkv}` vom Host gemountet — Worker `/root/.MakeMKV`, API `/app/makemkv-data`, @@ -466,6 +473,10 @@ funktionierende Weg ist eine `KEYDB.cfg` im MakeMKV-Datenverzeichnis. - [ ] Damit bleibt auch der volle Transcode-E2E an einer UHD weiter offen (siehe SAVEPOINT v3.7) — an normalen BD/DVD ist die Kette bewiesen. +**Nachtrag zu „Offen":** Beide Punkte sind mit Etappe 18 erledigt — Akira +ging auf der VM auf, allerdings über den Schlüsselspeicher statt über eine +`KEYDB.cfg`. + **Ausdrücklich nicht gebaut (und wird es auch nicht):** Rippy liefert keine Disc-Schlüssel mit, lädt keine herunter und verteilt keine. Es stellt nur den Platz für eine Datei bereit, die der Nutzer selbst @@ -473,6 +484,63 @@ mitbringt, und zeigt ehrlich an, was dort liegt. --- +## Etappe 18 (25.07.2026): 4K-UHD gelöst — Schlüsselspeicher statt KEYDB.cfg + +**Quelle:** Einwand des Commanders („wenn ich MakeMKV lokal auf meinem +Windows-PC installiere, würde es SOFORT gehen — wir übersehen etwas +Gewaltiges"). Er hatte recht. Gegenprobe mit demselben Laufwerk und +derselben Disc an einem Windows-PC: + +| | Linux (Worker) | Windows | +|---|---|---| +| Verbindungen beim Disc-Öffnen | **keine einzige** | 185.84.108.20:443 | +| Meldung 3338 „Downloading latest HK" | nie | ja | +| `_private_data.tar` | 2048 B, 0 Schlüssel | 6,4 MB, 604 Schlüssel | +| Disc | „volume key is unknown" | **TCOUNT:5, geht auf** | + +Gegengeprüft mit leerem UND gefülltem Speicher, mit und ohne `--noscan`, +mit `dev:/dev/sr0` und `disc:0`, mit gelöschter `update.conf`: Linux +fragt nie. Die Meldungsvorlage „Downloading latest %1 to %2 ..." steckt +sehr wohl im Linux-Binary — sie löst nur nicht aus. Gleiches Symptom im +MakeMKV-Forum, seit Jahren offen (t=25782, t=34022). +**Damit ist die Diagnose aus Etappe 17 („der Schlüssel-Kanal ist tot") +widerlegt.** Sie stützte sich auf zwei Hostnamen aus alten Forumsbeiträgen, +die MakeMKV längst nicht mehr benutzt. + +**Gebaut:** +- [x] **Schlüsselspeicher im Modul**: `zaehle_schluessel`, + `private_data_pruefen`, `schluesselspeicher_status`, + `private_data_schreiben` in `makemkv_daten.py` (beide Zwillinge). + Die Prüfung lehnt einen Speicher OHNE `hkd_*.bin` ab — sonst lädt + jemand den leeren Vorrat einer frischen Installation hoch, es ändert + sich nichts, und niemand versteht warum. +- [x] **API**: `GET /system/keystore` und `POST /system/keystore`. Der + Rohkörper der Anfrage IST die Datei — binär, deshalb kein JSON und + kein Base64; Multipart kann die API ohnehin nicht. +- [x] **UI**: neuer Block „Disc-Schlüssel für 4K-UHD" ÜBER dem + KEYDB-Block, mit Schlüssel-Anzahl, Upload und Schritt-für-Schritt- + Anleitung für den Windows-Umweg. KEYDB.cfg ist jetzt als Notnagel + beschriftet. Worker-Plakette zeigt die Schlüssel-Anzahl. +- [x] **Fehlertext** in `tasks.py` sagt den Windows-Weg an und nennt die + Anzahl bekannter Schlüssel dieses Workers. +- [x] **`caps.py`** meldet `schluessel` je Worker. +- [x] **Alle Falschaussagen korrigiert**: UI (3 Stellen), Anleitung (2), + README (3), KONZEPT §8 + §10, `makemkv_daten.py`-Modulkopf, + Worker-Dockerfile, `makemkv_key.py`. + +**Bewiesen:** Nach Übernahme des Windows-Schlüsselspeichers öffnet +`makemkvcon` auf der VM die Akira-UHD — „Operation successfully +completed", `TCOUNT:5`, fünf Titel, identisch zum Windows-Ergebnis. +**Das ist der erste belegte UHD-Disc-Zugriff auf der Rippy-Maschine.** + +**Offen aus dieser Runde:** +- [ ] Voller UHD-Rip inklusive Transcode-E2E (nur der Disc-Zugriff ist + belegt, nicht die komplette Kette bis zur fertigen Datei). +- [ ] Ob sich der Abruf unter Linux doch anstoßen lässt, ist ungeklärt — + der Code ist im Binary vorhanden. Bis dahin bleibt der Windows-Umweg. + +--- + ## Ideen-Katalog (Rest) — bewusst offen 1. **Design 2.0** — an Gemini übergeben (24.07.2026). Vollständiges diff --git a/SAVEPOINT.md b/SAVEPOINT.md index da00148..1a7185c 100644 --- a/SAVEPOINT.md +++ b/SAVEPOINT.md @@ -1,6 +1,69 @@ # SAVEPOINT — Rippy -## Aktueller Stand: v3.10 — 4K-UHD: KEYDB.cfg statt Warten auf MakeMKV (25.07.2026) +## Aktueller Stand: v3.11 — 4K-UHD GELÖST: Akira geht auf (25.07.2026) + +- **🎉 Der Durchbruch:** Nach Übernahme des Schlüsselspeichers öffnet + `makemkvcon` auf der VM die Akira-UHD: „Operation successfully + completed", **`TCOUNT:5`**, fünf Titel — identisch zum Windows-Ergebnis. + **Erster belegter UHD-Disc-Zugriff auf der Rippy-Maschine.** +- **Die echte Ursache — und sie ist eine andere als in v3.10:** + `makemkvcon` unter **Linux** ruft Disc-Schlüssel **nie** ab. Die + **Windows**-Version tut es. Gegenprobe mit demselben Laufwerk und + derselben Disc: + + | | Linux (Worker) | Windows | + |---|---|---| + | Verbindungen beim Disc-Öffnen | **keine einzige** | 185.84.108.20:443 | + | Meldung 3338 „Downloading latest HK" | nie | ja | + | `_private_data.tar` | 2048 B, **0** Schlüssel | 6,4 MB, **604** Schlüssel | + | Disc | „volume key is unknown" | **geht auf** | + + Gegengeprüft mit leerem UND gefülltem Speicher, mit und ohne `--noscan`, + mit `dev:/dev/sr0` und `disc:0`, mit gelöschter `update.conf`. Immer: + keine Verbindung. Die Meldungsvorlage „Downloading latest %1 to %2 ..." + steckt sehr wohl im Linux-Binary — sie löst nur nie aus. Gleiches + Symptom im MakeMKV-Forum, seit Jahren offen (t=25782, t=34022). +- **⚠️ Richtigstellung zu v3.10 (direkt darunter):** Dort steht, MakeMKVs + Schlüssel-Kanal sei abgeschaltet. **Das war falsch.** Die Herleitung + stützte sich auf zwei Hostnamen aus alten Forumsbeiträgen + (`hkdata.fairuse.org`, `hkdata.crabdance.com`), die tatsächlich nicht + mehr auflösen — MakeMKV benutzt sie aber längst nicht mehr. **Der Dienst + lebt, der Worker erreicht ihn sogar** (Verbindungstest auf + 185.84.108.20:443 erfolgreich); er wird unter Linux nur nie gefragt. + Aufgedeckt hat das der Commander mit dem Einwand, unter Windows ginge es + sofort. Alles in v3.10 Gebaute bleibt richtig und nötig — nur die + `KEYDB.cfg` ist nicht der Haupt-, sondern der Ersatzweg. +- **Gebaut — Schlüsselspeicher übernehmbar:** `GET`/`POST + /system/keystore` plus die Helfer in `makemkv_daten.py` (beide + Zwillinge). Der Rohkörper der Anfrage IST die Datei — binär, deshalb + kein JSON und kein Base64. Die Prüfung lehnt einen Speicher **ohne** + `hkd_*.bin` ab, sonst lädt jemand den leeren Vorrat einer frischen + Installation hoch und wundert sich, dass nichts passiert. +- **Gebaut — UI:** neuer Block „Disc-Schlüssel für 4K-UHD" **über** dem + KEYDB-Block, mit Schlüssel-Anzahl, Upload und der Schritt-für-Schritt- + Anleitung für den Windows-Umweg. KEYDB.cfg ist jetzt als **Notnagel** + beschriftet. Die Worker-Plakette zeigt die Anzahl bekannter Schlüssel; + `0` heißt sichtbar „4K-UHD scheitert". +- **Gebaut — ehrliche Texte:** Der UHD-Fehlertext nennt jetzt den + Windows-Weg und die Anzahl der Schlüssel dieses Workers. Alle + Falschaussagen korrigiert: UI (3 Stellen), Anleitung (2), README (3), + KONZEPT §8 + §10, Modulkopf von `makemkv_daten.py`, Worker-Dockerfile + und `makemkv_key.py` (dort stand: „Den AACS-Schlüssel zieht MakeMKV via + LibreDrive ohnehin selbst aus dem Laufwerk" — gilt für Blu-ray, NICHT + für UHD). +- **So hältst du den Vorrat aktuell:** Laufwerk an den Windows-PC, Disc in + MakeMKV öffnen, dann `_private_data.tar` aus dem MakeMKV-Datenverzeichnis + (*Preferences → General*) unter Einstellungen → System hochladen. Der + Speicher der Windows-Installation liegt bereits auf der VM unter + `/srv/rippy/makemkv/`. +- **Offen:** Der volle UHD-Rip inklusive Transcode-E2E ist noch nicht + durch — belegt ist der Disc-Zugriff, nicht die komplette Kette bis zur + fertigen Datei. Und ob sich der Abruf unter Linux doch anstoßen lässt, + ist ungeklärt; der Code dafür ist im Binary vorhanden. + +--- + +## Vorheriger Stand: v3.10 — 4K-UHD: KEYDB.cfg statt Warten auf MakeMKV (25.07.2026) - **Der Befund (am 25.07. live auf der VM im Worker-Container nachgemessen — kein Verdacht, alles belegt):** Eine 4K-UHD (Akira, diff --git a/docker/api/main.py b/docker/api/main.py index b2c0d9f..cbe4f34 100644 --- a/docker/api/main.py +++ b/docker/api/main.py @@ -1288,6 +1288,63 @@ async def delete_keydb(): return status +@app.get("/system/keystore") +async def get_keystore(): + """Wie viele Disc-Schlüssel kennt diese Rippy-Installation? + + Der Schlüsselspeicher (_private_data.tar) ist MakeMKVs eigener Vorrat. + Unter Windows füllt MakeMKV ihn selbst; unter Linux nie — deshalb muss er + hier von Hand hereingereicht werden (Befund 25.07.2026, siehe + makemkv_daten.py). Fehlt er, ist das der Normalfall: 200 mit + vorhanden=false, nie 404. + """ + def sammle(): + return makemkv_daten.schluesselspeicher_status() + + return await asyncio.to_thread(sammle) + + +@app.post("/system/keystore") +async def set_keystore(request: Request): + """Nimmt den Schlüsselspeicher einer MakeMKV-Installation entgegen. + + Der Rohkörper der Anfrage IST die Datei — bewusst kein Multipart-Upload + (python-multipart fehlt) und bewusst kein JSON: _private_data.tar ist + binär, und Base64 würde sie nur unnötig aufblähen. + + Wirkt ab dem NÄCHSTEN Rip: makemkvcon liest den Speicher beim Start. + """ + rohdaten = await request.body() + + def pruefe_und_schreibe(): + # Prüfung liest ein mehrere MB grosses tar — gehört deshalb mit in + # den Thread und nicht in die Ereignisschleife. + fehler = makemkv_daten.private_data_pruefen(rohdaten) + if fehler: + return fehler, None + return "", makemkv_daten.private_data_schreiben(rohdaten) + + try: + fehler, status = await asyncio.to_thread(pruefe_und_schreibe) + except OSError as e: + raise HTTPException( + status_code=500, + detail=( + f"Schlüsselspeicher konnte nicht geschrieben werden: {e}. " + "Prüfe, ob das MakeMKV-Datenverzeichnis auf der VM existiert " + "und beschreibbar ist (Standard: /srv/rippy/makemkv)." + ), + ) + if fehler: + raise HTTPException(status_code=422, detail=fehler) + await asyncio.to_thread( + db.add_log, "success", "makemkv-keydb", + f"Schlüsselspeicher übernommen: {status['schluessel']} Disc-Schlüssel, " + f"{status['groesse_bytes']} Bytes. Wirkt ab dem NÄCHSTEN Rip.", + ) + return status + + @app.get("/system/aacs-dumps") async def get_aacs_dumps(): """AACS-Dumps, die MakeMKV selbst abgelegt hat (neueste zuerst). diff --git a/docker/api/makemkv_daten.py b/docker/api/makemkv_daten.py index 1ce430d..936bb37 100644 --- a/docker/api/makemkv_daten.py +++ b/docker/api/makemkv_daten.py @@ -1,35 +1,51 @@ -"""MakeMKV-Datenverzeichnis: KEYDB.cfg, AACS-Dumps, settings.conf. +"""MakeMKV-Datenverzeichnis: Schluesselspeicher, KEYDB.cfg, AACS-Dumps. -WARUM ES DIESE DATEI GIBT (Befund 25.07.2026, live im Worker nachgemessen): -Bei 4K-UHD-Discs meldet MakeMKV "The volume key is unknown for this disc". -Das Laufwerk ist dabei in Ordnung — makemkvcon meldet "Using LibreDrive mode -(v06.3)" und liest die Disc — MakeMKV kennt nur den Schluessel DIESER Pressung -nicht. Und es holt ihn NICHT mehr online nach: +WARUM ES DIESE DATEI GIBT (Befund 25.07.2026, auf BEIDEN Maschinen gemessen): +4K-UHD-Discs scheiterten mit "The volume key is unknown for this disc". Die +Ursache ist weder die Disc noch das Laufwerk — LibreDrive v06.3 laeuft und +MakeMKV liest die Disc — sondern: - * /root/.MakeMKV/_private_data.tar enthielt ausser der Index-Datei keine - einzige hkd_*.bin, also nie einen heruntergeladenen Schluessel; - * auch mit erzwungener frischer Pruefung (update.conf geloescht, Meldung - 5074 belegt den Web-Kontakt) und mit app_UpdateEnable = "1" kam keiner; - * die im MakeMKV-Forum dokumentierten Schluessel-Server hkdata.fairuse.org - und hkdata.crabdance.com loesen weltweit nicht mehr auf (gegen Fritz!Box, - 8.8.8.8 und 1.1.1.1 geprueft: NXDOMAIN). + makemkvcon unter LINUX ruft die Disc-Schluessel nie ab. + Die Windows-Version tut es. -Betroffen war Akira UHD (MKB v76, Pressung von Dezember 2020) — also gerade -KEINE Neuerscheinung. Die bisherige Fehlermeldung ("Disc neuer als die -Schluessel-Datenbank, mit einem der naechsten Updates rippbar") war damit -schlicht falsch. +Gemessen, nicht vermutet: + * Linux: in KEINEM Lauf auch nur eine Verbindung nach draussen. Geprueft mit + leerem UND mit gefuelltem Schluesselspeicher, mit und ohne --noscan, mit + dev:/dev/sr0 und mit disc:0, und mit erzwungener frischer Pruefung + (update.conf geloescht, Meldung 5074 belegt den Web-Kontakt). Immer: + keine Verbindung, kein Schluessel. + * Windows, dieselbe Disc, dasselbe Laufwerk: Meldung 3338 "Downloading + latest HK to ...", Verbindung nach 185.84.108.20:443 + (web33.majordomo.ru), _private_data.tar waechst — und die Disc geht auf + (TCOUNT:5, "Operation successfully completed"). + * Der Code dafuer steckt auch im Linux-Binary: die Meldungsvorlage + "Downloading latest %1 to %2 ..." steht in makemkvcon. Sie loest nur nie + aus. Gleiches Symptom im Forum, seit Jahren offen und unbeantwortet. -Der einzige heute funktionierende Weg ist eine KEYDB.cfg im -MakeMKV-Datenverzeichnis. Rippy liefert KEINE Schluessel mit, laedt keine -herunter und verteilt keine — es stellt nur den Platz dafuer bereit und zeigt -ehrlich an, was dort liegt. Die Datei bringt der Nutzer selbst mit. +FRUEHERE FEHLDIAGNOSE, bewusst festgehalten: An dieser Stelle stand zuerst, +MakeMKVs Schluessel-Kanal sei abgeschaltet. Das war FALSCH. Die Herleitung +stuetzte sich auf zwei Hostnamen aus alten Forumsbeitraegen +(hkdata.fairuse.org, hkdata.crabdance.com), die tatsaechlich nicht mehr +aufloesen — MakeMKV benutzt sie aber laengst nicht mehr. Der Dienst lebt, der +Worker erreicht ihn sogar; er wird unter Linux nur nie gefragt. + +WAS DARAUS FOLGT: Der Schluesselspeicher (_private_data.tar) muss von einer +MakeMKV-Installation kommen, die ihn wirklich abruft — praktisch von Windows. +Rippy nimmt ihn unter Einstellungen -> System entgegen. Die KEYDB.cfg bleibt +der Notnagel fuer Pressungen, die auch MakeMKV selbst nicht kennt. + +Rippy liefert KEINE Schluessel mit, laedt keine herunter und verteilt keine. +Es verwaltet nur, was der Nutzer selbst mitbringt. QUELLEN (AGENTS Regel D — externe Schnittstellen nie aus dem Kopf): - * Datenverzeichnis und Dateiname GROSS geschrieben (unter Linux + * Linux laedt keine Hashed Keys — dasselbe Symptom, mehrfach berichtet: + https://forum.makemkv.com/forum/viewtopic.php?t=25782 + https://forum.makemkv.com/forum/viewtopic.php?t=34022 + * Schluessel liegen als hkd_*.bin in _private_data.tar: + https://forum.makemkv.com/forum/viewtopic.php?t=32675 + * Datenverzeichnis und Dateiname KEYDB.cfg GROSS geschrieben (unter Linux case-sensitiv), dort geloest mit "cp KEYDB.cfg ~/.MakeMKV/": https://forum.makemkv.com/forum/viewtopic.php?t=30636 - * Heruntergeladene Schluessel liegen als hkd_*.bin in _private_data.tar: - https://forum.makemkv.com/forum/viewtopic.php?t=32675 * Zeilenformat der KEYDB.cfg (libaacs): Disc-Kennung = 40 Hex-Zeichen, optional mit 0x-Praefix, dann "= Titel", danach optionale Felder wie "| V | <32 Hex>"; Zeilen ab ";" sind Kommentare: @@ -42,8 +58,10 @@ Images brauchen sie, ein gemeinsames Paket gibt es in diesem Projekt nicht (gleiche Lage wie bei db.py). Aenderungen IMMER in BEIDEN Dateien nachziehen. """ +import io import os import re +import tarfile from datetime import datetime, timezone # Container-Pfad aus der Umgebung: /root/.MakeMKV im Worker (nur dort sucht @@ -226,6 +244,121 @@ def dumps_auflisten(daten_dir: str = None) -> list: return liste +# --- Schluesselspeicher (_private_data.tar) ------------------------------- +# +# Das ist MakeMKVs eigener Speicher fuer die "Hashed Keys": ein tar-Archiv mit +# hkd_*.bin-Eintraegen. Unter Windows fuellt MakeMKV es selbst (Meldung 3338), +# unter Linux nie — siehe Modul-Kopf. Rippy nimmt die Datei deshalb entgegen +# und legt sie ins Datenverzeichnis; MakeMKV liest sie beim naechsten Start. + +PRIVATE_DATA_NAME = "_private_data.tar" + +# Der Speicher lag am 25.07.2026 bei rund 6 MB und waechst mit jeder neuen +# Pressung. 64 MB sind reichlich Luft — und derselbe Wert wie +# client_max_body_size in docker/ui/nginx.conf: waere die Grenze hier hoeher, +# wuerde nginx den Upload abweisen, bevor die API ihn ueberhaupt sieht. +MAX_PRIVATE_DATA_BYTES = 64 * 1024 * 1024 + + +def private_data_pfad(daten_dir: str = None) -> str: + """Voller Pfad zum Schluesselspeicher im Datenverzeichnis.""" + return os.path.join(daten_dir or DATEN_DIR, PRIVATE_DATA_NAME) + + +def zaehle_schluessel(rohdaten: bytes) -> int: + """Anzahl der hkd_*.bin-Eintraege im Archiv (pure Funktion, testbar). + + Das ist die ehrliche Kennzahl fuer "wie viele Disc-Schluessel kennt diese + Installation". Ein frischer, leerer Speicher enthaelt nur eine + Index-Datei und kommt hier auf 0 — genau der Zustand, in dem jede + unbekannte UHD-Disc scheitert. + """ + try: + with tarfile.open(fileobj=io.BytesIO(rohdaten)) as archiv: + return sum(1 for name in archiv.getnames() if name.startswith("hkd_")) + except (tarfile.TarError, OSError, EOFError): + return 0 + + +def private_data_pruefen(rohdaten: bytes) -> str: + """Prueft hochgeladene Rohdaten; deutscher Fehlertext oder "". + + Faengt die beiden Bedienfehler ab, die sonst still danebengehen: eine + voellig andere Datei hochladen, oder den Speicher einer Installation, die + selbst noch keine Schluessel geholt hat (dann aendert sich nichts, und + niemand versteht warum). + """ + if not rohdaten: + return "Die Datei ist leer." + if len(rohdaten) > MAX_PRIVATE_DATA_BYTES: + return ( + "Die Datei ist groesser als " + f"{MAX_PRIVATE_DATA_BYTES // (1024 * 1024)} MB — das ist kein " + "MakeMKV-Schluesselspeicher." + ) + try: + with tarfile.open(fileobj=io.BytesIO(rohdaten)) as archiv: + namen = archiv.getnames() + except (tarfile.TarError, OSError, EOFError): + return ( + "Das ist kein tar-Archiv. Erwartet wird die Datei " + f"{PRIVATE_DATA_NAME} aus dem MakeMKV-Datenverzeichnis." + ) + if not any(name.startswith("hkd_") for name in namen): + return ( + "In dieser Datei steckt kein einziger Schluessel (kein hkd_*.bin). " + "Sie stammt vermutlich von einer MakeMKV-Installation, die selbst " + "noch keine geholt hat — oeffne dort erst einmal eine Disc." + ) + return "" + + +def schluesselspeicher_status(daten_dir: str = None) -> dict: + """Zustand des Schluesselspeichers. Fehlt er, ist das kein Fehler.""" + pfad = private_data_pfad(daten_dir) + try: + angaben = os.stat(pfad) + with open(pfad, "rb") as datei: + schluessel = zaehle_schluessel(datei.read()) + except OSError: + return { + "vorhanden": False, + "pfad": pfad, + "groesse_bytes": 0, + "schluessel": 0, + "geaendert": "", + } + return { + "vorhanden": True, + "pfad": pfad, + "groesse_bytes": angaben.st_size, + "schluessel": schluessel, + "geaendert": _iso(angaben.st_mtime), + } + + +def private_data_schreiben(rohdaten: bytes, daten_dir: str = None) -> dict: + """Legt den Schluesselspeicher atomar ab und meldet den neuen Zustand. + + Atomar aus demselben Grund wie bei der KEYDB.cfg: waehrend ein Rip laeuft, + darf makemkvcon nie ein halb geschriebenes Archiv sehen. + """ + pfad = private_data_pfad(daten_dir) + os.makedirs(os.path.dirname(pfad), exist_ok=True) + neben = pfad + ".neu" + try: + with open(neben, "wb") as datei: + datei.write(rohdaten) + os.replace(neben, pfad) + except OSError: + try: + os.remove(neben) + except OSError: + pass + raise + return schluesselspeicher_status(daten_dir) + + def settings_conf_zusammenfuehren(inhalt: str, key: str) -> str: """app_Key setzen, ohne den Rest der settings.conf zu verlieren (pure). diff --git a/docker/api/test_api_smoke.py b/docker/api/test_api_smoke.py index ef683bc..93d06ed 100644 --- a/docker/api/test_api_smoke.py +++ b/docker/api/test_api_smoke.py @@ -24,6 +24,9 @@ def test_main_importierbar_und_routen_verdrahtet(): # Schlüsseldatei (Befund 25.07.2026 — MakeMKV holt UHD-Schlüssel nicht # mehr online nach). Ohne diese Routen ist die Seite im UI tot. "/system/keydb", "/system/aacs-dumps", "/system/aacs-dumps/{dateiname}", + # Der Hauptweg fuer 4K-UHD (25.07.2026): makemkvcon holt Disc-Schluessel + # unter Linux nie selbst, sie kommen von Hand ueber diesen Endpunkt. + "/system/keystore", ): assert pfad in routen, f"Route {pfad} fehlt" diff --git a/docker/ui/src/pages/Anleitung.tsx b/docker/ui/src/pages/Anleitung.tsx index 9a8ba96..2f7fc7a 100644 --- a/docker/ui/src/pages/Anleitung.tsx +++ b/docker/ui/src/pages/Anleitung.tsx @@ -141,8 +141,8 @@ export default function AnleitungPage() { HandBrake-Releases. Gibt es ein MakeMKV-Update, zeigt Rippy den fertigen Update-Befehl an — neue Versionen bringen bessere Laufwerks-Unterstützung und Fehlerbehebungen. Disc-Schlüssel für 4K-UHD kommen dagegen nicht - aus einem Update, sondern nur aus der Datei KEYDB.cfg, die du selbst - unter Einstellungen → System hochlädst (mehr dazu unter „Häufige Fragen"). + aus einem Update — die holt MakeMKV zur Laufzeit, und die Linux-Version tut das + nie. Wie du sie trotzdem bekommst, steht unter „Häufige Fragen".

@@ -161,30 +161,34 @@ export default function AnleitungPage() { Fingerabdruck. Nochmal rippen geht trotzdem — der Hinweis verhindert nur Versehen.

{/* - 25.07.2026 auf der Rippy-VM nachgemessen und komplett neu geschrieben: - Hier stand vorher, ein MakeMKV-Update mache die Disc rippbar. Das stimmt - nicht — MakeMKV versucht bei einer unbekannten UHD-Pressung gar nicht mehr, - online einen Schluessel zu holen, und die dokumentierten Schluessel-Server - (hkdata.fairuse.org, hkdata.crabdance.com) loesen weltweit nicht mehr auf. + 25.07.2026 auf BEIDEN Maschinen nachgemessen und erneut korrigiert. Es + stand hier nacheinander zweierlei Falsches: erst "ein MakeMKV-Update macht + die Disc rippbar", dann "MakeMKVs Schluessel-Kanal ist tot". Richtig ist: + makemkvcon unter Linux ruft die Schluessel nie ab, die Windows-Version + schon (Meldung 3338, Verbindung nach 185.84.108.20:443). */}

4K-UHD schlägt fehl mit „volume key is unknown"? Das Laufwerk liest die Disc einwandfrei (LibreDrive) — MakeMKV fehlt nur der Schlüssel dieser Pressung. - Früher holte MakeMKV solche Schlüssel selbst aus dem Netz; dieser Kanal liefert heute nichts - mehr, und ein MakeMKV-Update ändert daran nichts. + Der Grund liegt nicht bei dir und nicht bei Rippy: die Linux-Version + von MakeMKV holt Disc-Schlüssel nie selbst aus dem Netz. Die Windows-Version tut es. + Ein MakeMKV-Update ändert daran nichts.

- Der einzige Weg, der heute funktioniert, ist eine Datei namens KEYDB.cfg — - eine Textliste mit Disc-Schlüsseln, die du selbst mitbringst. Unter Einstellungen → System - hochladen, sie wirkt ab dem nächsten Rip. Rippy liefert keine - Schlüssel mit und lädt auch keine herunter — Rippy stellt nur den Platz für deine - Datei bereit und zeigt dir an, was dort liegt. + Der Weg drumherum: MakeMKV einmalig auf einem Windows-PC + installieren (gleicher Beta-Key), das Laufwerk dort anstecken, die Disc öffnen — MakeMKV + lädt die Schlüssel dabei nach. Dann in MakeMKV unter Preferences → General das + „MakeMKV data directory" nachschlagen und die Datei _private_data.tar daraus + bei Rippy unter Einstellungen → System hochladen. Wirkt ab dem nächsten Rip. Für neue + Discs gelegentlich wiederholen — der Block dort zeigt dir, wie viele Schlüssel Rippy kennt.

- Der AACS-Dump zu einer gescheiterten Disc bleibt jetzt - erhalten und steht unter Einstellungen → System zum Herunterladen. Ihn kannst du im - MakeMKV-Forum im Bereich „Ultra HD Blu-ray" einreichen — daraus lässt sich der Schlüssel - für deine Pressung ermitteln, den du dann in deine KEYDB.cfg einträgst. + Geht eine Pressung auch damit nicht auf, kennt MakeMKV sie selbst nicht. Dann bleiben zwei + Dinge: eine KEYDB.cfg (ebenfalls dort hochladbar, der Notnagel), oder den + AACS-Dump im MakeMKV-Forum im Bereich „Ultra HD Blu-ray" + einreichen — der bleibt jetzt erhalten und steht unter Einstellungen → System zum + Herunterladen. Rippy liefert keine Schlüssel mit und lädt keine + herunter — es verwaltet nur, was du selbst mitbringst.

„Neu komprimieren" fehlt bei einem Fehl-Job? Der Knopf diff --git a/docker/ui/src/pages/Settings.tsx b/docker/ui/src/pages/Settings.tsx index 80487d4..12e8d26 100644 --- a/docker/ui/src/pages/Settings.tsx +++ b/docker/ui/src/pages/Settings.tsx @@ -77,6 +77,15 @@ interface KeydbStatus { geaendert: string } +// Antwort von GET/POST /system/keystore — MakeMKVs eigener Schluesselvorrat. +interface KeystoreStatus { + vorhanden: boolean + pfad: string + groesse_bytes: number + schluessel: number + geaendert: string +} + // Ein AACS-Dump aus GET /system/aacs-dumps. interface AacsDump { name: string @@ -130,6 +139,9 @@ export default function SettingsPage() { const [keydbBusy, setKeydbBusy] = useState(false) const [dumps, setDumps] = useState([]) const keydbInput = useRef(null) + const [keystore, setKeystore] = useState(null) + const [keystoreBusy, setKeystoreBusy] = useState(false) + const keystoreInput = useRef(null) const { toast } = useToast() @@ -155,6 +167,7 @@ export default function SettingsPage() { // nicht das, was wir gerade hochgeschickt haben. const keydbLaden = () => { api.get('/system/keydb').then(r => setKeydb(r.data)).catch(() => setKeydb(null)) + api.get('/system/keystore').then(r => setKeystore(r.data)).catch(() => setKeystore(null)) api.get('/system/aacs-dumps').then(r => setDumps(r.data?.dumps || [])).catch(() => setDumps([])) // Die Worker-Plaketten oben kommen aus /capabilities und stammen aus dem // letzten Herzschlag des Workers (minuetlich) — ohne dieses Nachladen @@ -180,6 +193,25 @@ export default function SettingsPage() { } } + const keystoreHochladen = async (datei: File) => { + setKeystoreBusy(true) + try { + // Die Datei wandert als roher Anfrage-Körper zur API — _private_data.tar + // ist binär, JSON oder Base64 wäre nur unnötiger Ballast, und Multipart + // kann die API nicht (kein python-multipart). + await api.post('/system/keystore', datei, { + headers: { 'Content-Type': 'application/octet-stream' }, + }) + keydbLaden() + toast('success', 'Schlüsselspeicher übernommen — wirkt ab dem nächsten Rip.') + } catch (e: any) { + toast('error', e?.response?.data?.detail + || 'Übernahme fehlgeschlagen — ist das wirklich die Datei _private_data.tar, und läuft die API?') + } finally { + setKeystoreBusy(false) + } + } + const keydbEntfernen = async () => { setKeydbBusy(true) try { @@ -221,6 +253,9 @@ export default function SettingsPage() { api.get('/system/keydb') .then(r => setKeydb(r.data)) .catch(() => setKeydb(null)) + api.get('/system/keystore') + .then(r => setKeystore(r.data)) + .catch(() => setKeystore(null)) api.get('/system/aacs-dumps') .then(r => setDumps(r.data?.dumps || [])) .catch(() => setDumps([])) @@ -726,20 +761,24 @@ export default function SettingsPage() { HandBrake {w.info.handbrake} )} - {/* Nur das Verzeichnis des rippenden Workers zaehlt — deshalb je Worker. */} - {w.info?.keydb === 'ja' && ( + {/* + Nur das Verzeichnis des rippenden Workers zaehlt — deshalb je Worker. + Die Zahl der Disc-Schluessel ist die entscheidende Angabe fuer 4K-UHD: + 0 heisst, dass JEDE unbekannte UHD-Disc scheitert. + */} + {w.info?.schluessel && w.info.schluessel !== '0' && w.info.schluessel !== 'unbekannt' && ( - KEYDB.cfg vorhanden + {w.info.schluessel} Disc-Schlüssel )} - {w.info?.keydb === 'nein' && ( + {w.info?.schluessel === '0' && ( - keine KEYDB.cfg + keine Disc-Schlüssel — 4K-UHD scheitert )} - {w.info?.keydb === 'unbekannt' && ( + {w.info?.keydb === 'ja' && ( - KEYDB.cfg unbekannt + + KEYDB.cfg )} @@ -747,19 +786,17 @@ export default function SettingsPage() { )} {/* Bis 25.07.2026 stand hier, MakeMKV-Updates braechten die neueste - Disc-Schluessel-Datenbank mit. Auf der Rippy-VM nachgemessen: falsch. - MakeMKV hat gar keine mitgelieferte Schluessel-Datenbank, und der - Online-Kanal liefert nichts mehr (die Server hkdata.fairuse.org und - hkdata.crabdance.com loesen weltweit nicht mehr auf). Updates bringen - Laufwerks-Firmware-Unterstuetzung und Fehlerbehebungen — Schluessel - fuer neue UHD-Pressungen kommen ausschliesslich aus der KEYDB.cfg. + Disc-Schluessel-Datenbank mit. Nachgemessen: falsch — MakeMKV liefert + gar keine Schluessel mit, es holt sie zur Laufzeit. Und die + Linux-Version holt sie nie (kein einziger Verbindungsversuch, auf + beiden Maschinen verglichen). Deshalb der Schluesselspeicher unten. */}

MakeMKV lässt sich aktuell halten (Update-Check unten; Version über MAKEMKV_VERSION + Rebuild) — neue Versionen bringen - vor allem Laufwerks-Unterstützung und Fehlerbehebungen. Disc-Schlüssel für neue - 4K-UHD-Pressungen kommen dagegen NICHT aus einem Update, sondern nur aus der KEYDB.cfg - im Block darunter. + vor allem Laufwerks-Unterstützung und Fehlerbehebungen. Disc-Schlüssel für 4K-UHD kommen + NICHT aus einem Update — die holt MakeMKV zur Laufzeit, und die Linux-Version tut das + nie. Deshalb der Block „Disc-Schlüssel für 4K-UHD" weiter unten. {' '}HandBrake im eingebauten Docker-Worker ist bewusst die stabile Debian-Version — für die Kompression völlig ausreichend und wird nicht separat aktualisiert. Native Worker (Windows) holen @@ -776,18 +813,91 @@ export default function SettingsPage() { /> {/* - MakeMKV-Schluessel (KEYDB.cfg) — Befund vom 25.07.2026 auf der Rippy-VM: - MakeMKV versucht bei einer unbekannten UHD-Pressung gar nicht mehr, online - einen Schluessel zu holen, und die dokumentierten Schluessel-Server sind tot. - Der einzige heute funktionierende Weg ist eine Datei KEYDB.cfg (GROSS - geschrieben, unter Linux case-sensitiv) im MakeMKV-Datenverzeichnis. - Rippy stellt nur den Platz dafuer bereit — mitgeliefert wird nichts. + Schluesselspeicher — der Hauptweg fuer 4K-UHD (Befund 25.07.2026, + auf beiden Maschinen gemessen): makemkvcon holt Disc-Schluessel + unter Linux NIE selbst, die Windows-Version tut es (Meldung 3338, + Verbindung nach 185.84.108.20:443). Deshalb wird der Vorrat hier + von Hand hereingereicht. Frueher stand an dieser Stelle die These, + MakeMKVs Schluessel-Kanal sei abgeschaltet — das war falsch. + */} +

+
+

+ + Disc-Schlüssel für 4K-UHD +

+
+ { + const datei = e.target.files?.[0] + e.target.value = '' + if (datei) keystoreHochladen(datei) + }} + /> + +
+
+ + {keystore?.vorhanden && keystore.schluessel > 0 ? ( +
+

{keystore.schluessel} Disc-Schlüssel vorhanden.

+

+ {bytesLesbar(keystore.groesse_bytes)} · zuletzt geändert {zeitLesbar(keystore.geaendert)} +

+
+ ) : ( +
+

Kein einziger Disc-Schlüssel vorhanden.

+

+ DVDs und normale Blu-rays laufen trotzdem. 4K-UHD-Discs scheitern dagegen mit + „The volume key is unknown for this disc" — solange hier nichts liegt, jede einzelne. +

+
+ )} + +

+ Warum das nötig ist: MakeMKV + holt sich diese Schlüssel eigentlich selbst aus dem Netz. Die Linux-Version tut das + nicht — am 25.07.2026 nachgemessen: sie baut dabei nicht eine einzige Verbindung auf. + Die Windows-Version schon. Ein MakeMKV-Update ändert daran nichts, es ist kein Fehler in Rippy. +

+

+ So füllst du den Vorrat: MakeMKV + auf einem Windows-PC installieren (gleicher Beta-Key), das Laufwerk dort anstecken und die Disc + einmal öffnen. MakeMKV lädt die Schlüssel dabei nach. Danach unter Preferences → General + das „MakeMKV data directory" nachschlagen, die Datei _private_data.tar daraus hier + hochladen — fertig. Für neue Discs von Zeit zu Zeit wiederholen. +

+

+ Das ist der Zwischenspeicher deiner + eigenen MakeMKV-Installation, über MakeMKVs offiziellen Weg mit deiner eigenen Lizenz + geholt. Rippy liefert keine Schlüssel mit und lädt keine herunter. +

+
+ + {/* + KEYDB.cfg — der NOTNAGEL, nicht der Hauptweg. Sie hilft bei Pressungen, + die auch MakeMKV selbst nicht kennt. Der Regelfall laeuft ueber den + Schluesselspeicher im Block darueber. Dateiname GROSS geschrieben, unter + Linux case-sensitiv. Rippy stellt nur den Platz bereit. */}

- MakeMKV-Schlüssel (KEYDB.cfg) + KEYDB.cfg (Notnagel)

{/* @@ -834,20 +944,20 @@ export default function SettingsPage() {

{keydb.pfad}

) : ( -
-

Es liegt keine KEYDB.cfg bereit.

+
+

Keine KEYDB.cfg hinterlegt.

- DVDs und normale Blu-rays laufen trotzdem. Nur bei 4K-UHD-Discs, deren Schlüssel MakeMKV - nicht kennt, bricht der Rip mit „The volume key is unknown for this disc" ab. + Das ist normal und meistens auch nicht nötig — der Regelfall läuft über den + Schlüsselspeicher oben.

)}

Die KEYDB.cfg ist eine reine - Textdatei mit Disc-Schlüsseln für 4K-UHD-Blu-rays. MakeMKV holte solche Schlüssel früher selbst - aus dem Netz — das funktioniert heute nicht mehr, die alten Schlüssel-Server sind abgeschaltet. - Ein MakeMKV-Update hilft dagegen nicht. + Textdatei mit Disc-Schlüsseln. Sie ist der + Notnagel für den Fall, dass eine Pressung selbst über den Schlüsselspeicher nicht + aufgeht — also auch MakeMKV sie nicht kennt. Zuerst immer den Weg darüber versuchen.

Wichtig: Rippy liefert keine @@ -926,9 +1036,9 @@ export default function SettingsPage() {

⚠️ Update verfügbar — in der .env MAKEMKV_VERSION={updates.makemkv.verfuegbar} setzen, dann auf der Rippy-Maschine docker compose build worker && docker compose up -d worker. - {/* 25.07.2026 richtiggestellt: ein Update bringt KEINE Schluessel — die kommen nur aus der KEYDB.cfg. */} + {/* 25.07.2026 richtiggestellt: ein Update bringt KEINE Disc-Schluessel mit. */} Neue Versionen bringen Laufwerks-Unterstützung und Fehlerbehebungen — aber - keine Disc-Schlüssel: die kommen ausschließlich aus deiner KEYDB.cfg. + keine Disc-Schlüssel: die kommen aus dem Schlüsselspeicher.

) : ✓ aktuell} diff --git a/docker/worker/caps.py b/docker/worker/caps.py index 1a56688..791198e 100644 --- a/docker/worker/caps.py +++ b/docker/worker/caps.py @@ -105,4 +105,11 @@ def werkzeug_versionen() -> dict: info["keydb"] = "ja" if makemkv_daten.keydb_status().get("vorhanden") else "nein" except Exception: info["keydb"] = "unbekannt" + # Die entscheidende Zahl für 4K-UHD: wie viele Disc-Schlüssel kennt + # dieser Worker? 0 heißt, dass jede unbekannte UHD-Disc scheitert — + # makemkvcon holt sie unter Linux nie selbst (Befund 25.07.2026). + try: + info["schluessel"] = str(makemkv_daten.schluesselspeicher_status().get("schluessel", 0)) + except Exception: + info["schluessel"] = "unbekannt" return info diff --git a/docker/worker/makemkv_daten.py b/docker/worker/makemkv_daten.py index 1ce430d..936bb37 100644 --- a/docker/worker/makemkv_daten.py +++ b/docker/worker/makemkv_daten.py @@ -1,35 +1,51 @@ -"""MakeMKV-Datenverzeichnis: KEYDB.cfg, AACS-Dumps, settings.conf. +"""MakeMKV-Datenverzeichnis: Schluesselspeicher, KEYDB.cfg, AACS-Dumps. -WARUM ES DIESE DATEI GIBT (Befund 25.07.2026, live im Worker nachgemessen): -Bei 4K-UHD-Discs meldet MakeMKV "The volume key is unknown for this disc". -Das Laufwerk ist dabei in Ordnung — makemkvcon meldet "Using LibreDrive mode -(v06.3)" und liest die Disc — MakeMKV kennt nur den Schluessel DIESER Pressung -nicht. Und es holt ihn NICHT mehr online nach: +WARUM ES DIESE DATEI GIBT (Befund 25.07.2026, auf BEIDEN Maschinen gemessen): +4K-UHD-Discs scheiterten mit "The volume key is unknown for this disc". Die +Ursache ist weder die Disc noch das Laufwerk — LibreDrive v06.3 laeuft und +MakeMKV liest die Disc — sondern: - * /root/.MakeMKV/_private_data.tar enthielt ausser der Index-Datei keine - einzige hkd_*.bin, also nie einen heruntergeladenen Schluessel; - * auch mit erzwungener frischer Pruefung (update.conf geloescht, Meldung - 5074 belegt den Web-Kontakt) und mit app_UpdateEnable = "1" kam keiner; - * die im MakeMKV-Forum dokumentierten Schluessel-Server hkdata.fairuse.org - und hkdata.crabdance.com loesen weltweit nicht mehr auf (gegen Fritz!Box, - 8.8.8.8 und 1.1.1.1 geprueft: NXDOMAIN). + makemkvcon unter LINUX ruft die Disc-Schluessel nie ab. + Die Windows-Version tut es. -Betroffen war Akira UHD (MKB v76, Pressung von Dezember 2020) — also gerade -KEINE Neuerscheinung. Die bisherige Fehlermeldung ("Disc neuer als die -Schluessel-Datenbank, mit einem der naechsten Updates rippbar") war damit -schlicht falsch. +Gemessen, nicht vermutet: + * Linux: in KEINEM Lauf auch nur eine Verbindung nach draussen. Geprueft mit + leerem UND mit gefuelltem Schluesselspeicher, mit und ohne --noscan, mit + dev:/dev/sr0 und mit disc:0, und mit erzwungener frischer Pruefung + (update.conf geloescht, Meldung 5074 belegt den Web-Kontakt). Immer: + keine Verbindung, kein Schluessel. + * Windows, dieselbe Disc, dasselbe Laufwerk: Meldung 3338 "Downloading + latest HK to ...", Verbindung nach 185.84.108.20:443 + (web33.majordomo.ru), _private_data.tar waechst — und die Disc geht auf + (TCOUNT:5, "Operation successfully completed"). + * Der Code dafuer steckt auch im Linux-Binary: die Meldungsvorlage + "Downloading latest %1 to %2 ..." steht in makemkvcon. Sie loest nur nie + aus. Gleiches Symptom im Forum, seit Jahren offen und unbeantwortet. -Der einzige heute funktionierende Weg ist eine KEYDB.cfg im -MakeMKV-Datenverzeichnis. Rippy liefert KEINE Schluessel mit, laedt keine -herunter und verteilt keine — es stellt nur den Platz dafuer bereit und zeigt -ehrlich an, was dort liegt. Die Datei bringt der Nutzer selbst mit. +FRUEHERE FEHLDIAGNOSE, bewusst festgehalten: An dieser Stelle stand zuerst, +MakeMKVs Schluessel-Kanal sei abgeschaltet. Das war FALSCH. Die Herleitung +stuetzte sich auf zwei Hostnamen aus alten Forumsbeitraegen +(hkdata.fairuse.org, hkdata.crabdance.com), die tatsaechlich nicht mehr +aufloesen — MakeMKV benutzt sie aber laengst nicht mehr. Der Dienst lebt, der +Worker erreicht ihn sogar; er wird unter Linux nur nie gefragt. + +WAS DARAUS FOLGT: Der Schluesselspeicher (_private_data.tar) muss von einer +MakeMKV-Installation kommen, die ihn wirklich abruft — praktisch von Windows. +Rippy nimmt ihn unter Einstellungen -> System entgegen. Die KEYDB.cfg bleibt +der Notnagel fuer Pressungen, die auch MakeMKV selbst nicht kennt. + +Rippy liefert KEINE Schluessel mit, laedt keine herunter und verteilt keine. +Es verwaltet nur, was der Nutzer selbst mitbringt. QUELLEN (AGENTS Regel D — externe Schnittstellen nie aus dem Kopf): - * Datenverzeichnis und Dateiname GROSS geschrieben (unter Linux + * Linux laedt keine Hashed Keys — dasselbe Symptom, mehrfach berichtet: + https://forum.makemkv.com/forum/viewtopic.php?t=25782 + https://forum.makemkv.com/forum/viewtopic.php?t=34022 + * Schluessel liegen als hkd_*.bin in _private_data.tar: + https://forum.makemkv.com/forum/viewtopic.php?t=32675 + * Datenverzeichnis und Dateiname KEYDB.cfg GROSS geschrieben (unter Linux case-sensitiv), dort geloest mit "cp KEYDB.cfg ~/.MakeMKV/": https://forum.makemkv.com/forum/viewtopic.php?t=30636 - * Heruntergeladene Schluessel liegen als hkd_*.bin in _private_data.tar: - https://forum.makemkv.com/forum/viewtopic.php?t=32675 * Zeilenformat der KEYDB.cfg (libaacs): Disc-Kennung = 40 Hex-Zeichen, optional mit 0x-Praefix, dann "= Titel", danach optionale Felder wie "| V | <32 Hex>"; Zeilen ab ";" sind Kommentare: @@ -42,8 +58,10 @@ Images brauchen sie, ein gemeinsames Paket gibt es in diesem Projekt nicht (gleiche Lage wie bei db.py). Aenderungen IMMER in BEIDEN Dateien nachziehen. """ +import io import os import re +import tarfile from datetime import datetime, timezone # Container-Pfad aus der Umgebung: /root/.MakeMKV im Worker (nur dort sucht @@ -226,6 +244,121 @@ def dumps_auflisten(daten_dir: str = None) -> list: return liste +# --- Schluesselspeicher (_private_data.tar) ------------------------------- +# +# Das ist MakeMKVs eigener Speicher fuer die "Hashed Keys": ein tar-Archiv mit +# hkd_*.bin-Eintraegen. Unter Windows fuellt MakeMKV es selbst (Meldung 3338), +# unter Linux nie — siehe Modul-Kopf. Rippy nimmt die Datei deshalb entgegen +# und legt sie ins Datenverzeichnis; MakeMKV liest sie beim naechsten Start. + +PRIVATE_DATA_NAME = "_private_data.tar" + +# Der Speicher lag am 25.07.2026 bei rund 6 MB und waechst mit jeder neuen +# Pressung. 64 MB sind reichlich Luft — und derselbe Wert wie +# client_max_body_size in docker/ui/nginx.conf: waere die Grenze hier hoeher, +# wuerde nginx den Upload abweisen, bevor die API ihn ueberhaupt sieht. +MAX_PRIVATE_DATA_BYTES = 64 * 1024 * 1024 + + +def private_data_pfad(daten_dir: str = None) -> str: + """Voller Pfad zum Schluesselspeicher im Datenverzeichnis.""" + return os.path.join(daten_dir or DATEN_DIR, PRIVATE_DATA_NAME) + + +def zaehle_schluessel(rohdaten: bytes) -> int: + """Anzahl der hkd_*.bin-Eintraege im Archiv (pure Funktion, testbar). + + Das ist die ehrliche Kennzahl fuer "wie viele Disc-Schluessel kennt diese + Installation". Ein frischer, leerer Speicher enthaelt nur eine + Index-Datei und kommt hier auf 0 — genau der Zustand, in dem jede + unbekannte UHD-Disc scheitert. + """ + try: + with tarfile.open(fileobj=io.BytesIO(rohdaten)) as archiv: + return sum(1 for name in archiv.getnames() if name.startswith("hkd_")) + except (tarfile.TarError, OSError, EOFError): + return 0 + + +def private_data_pruefen(rohdaten: bytes) -> str: + """Prueft hochgeladene Rohdaten; deutscher Fehlertext oder "". + + Faengt die beiden Bedienfehler ab, die sonst still danebengehen: eine + voellig andere Datei hochladen, oder den Speicher einer Installation, die + selbst noch keine Schluessel geholt hat (dann aendert sich nichts, und + niemand versteht warum). + """ + if not rohdaten: + return "Die Datei ist leer." + if len(rohdaten) > MAX_PRIVATE_DATA_BYTES: + return ( + "Die Datei ist groesser als " + f"{MAX_PRIVATE_DATA_BYTES // (1024 * 1024)} MB — das ist kein " + "MakeMKV-Schluesselspeicher." + ) + try: + with tarfile.open(fileobj=io.BytesIO(rohdaten)) as archiv: + namen = archiv.getnames() + except (tarfile.TarError, OSError, EOFError): + return ( + "Das ist kein tar-Archiv. Erwartet wird die Datei " + f"{PRIVATE_DATA_NAME} aus dem MakeMKV-Datenverzeichnis." + ) + if not any(name.startswith("hkd_") for name in namen): + return ( + "In dieser Datei steckt kein einziger Schluessel (kein hkd_*.bin). " + "Sie stammt vermutlich von einer MakeMKV-Installation, die selbst " + "noch keine geholt hat — oeffne dort erst einmal eine Disc." + ) + return "" + + +def schluesselspeicher_status(daten_dir: str = None) -> dict: + """Zustand des Schluesselspeichers. Fehlt er, ist das kein Fehler.""" + pfad = private_data_pfad(daten_dir) + try: + angaben = os.stat(pfad) + with open(pfad, "rb") as datei: + schluessel = zaehle_schluessel(datei.read()) + except OSError: + return { + "vorhanden": False, + "pfad": pfad, + "groesse_bytes": 0, + "schluessel": 0, + "geaendert": "", + } + return { + "vorhanden": True, + "pfad": pfad, + "groesse_bytes": angaben.st_size, + "schluessel": schluessel, + "geaendert": _iso(angaben.st_mtime), + } + + +def private_data_schreiben(rohdaten: bytes, daten_dir: str = None) -> dict: + """Legt den Schluesselspeicher atomar ab und meldet den neuen Zustand. + + Atomar aus demselben Grund wie bei der KEYDB.cfg: waehrend ein Rip laeuft, + darf makemkvcon nie ein halb geschriebenes Archiv sehen. + """ + pfad = private_data_pfad(daten_dir) + os.makedirs(os.path.dirname(pfad), exist_ok=True) + neben = pfad + ".neu" + try: + with open(neben, "wb") as datei: + datei.write(rohdaten) + os.replace(neben, pfad) + except OSError: + try: + os.remove(neben) + except OSError: + pass + raise + return schluesselspeicher_status(daten_dir) + + def settings_conf_zusammenfuehren(inhalt: str, key: str) -> str: """app_Key setzen, ohne den Rest der settings.conf zu verlieren (pure). diff --git a/docker/worker/tasks.py b/docker/worker/tasks.py index a95e0a6..266b1af 100644 --- a/docker/worker/tasks.py +++ b/docker/worker/tasks.py @@ -455,33 +455,34 @@ def rip_disc(self, device_path: str, job_id: str, target_dir: str = None): if ergebnis.get("status") == "error": fehler_text = ergebnis.get("error") or "" if "volume key is unknown" in fehler_text: - # Befund 25.07.2026, im Worker nachgemessen (Akira UHD, MKB v76, - # Pressung Dez. 2020): Laufwerk und MakeMKV sind in Ordnung — - # MakeMKV fragt online gar nicht erst nach einem Schlüssel, und - # der Online-Kanal liefert auch nichts mehr. Der alte Text hier - # ("Disc neuer als die Schlüssel-Datenbank, mit einem der - # nächsten Updates rippbar") war schlicht falsch und hat in die - # falsche Richtung geschickt. Details: makemkv_daten.py. - keydb = makemkv_daten.keydb_status() + # Befund 25.07.2026, auf BEIDEN Maschinen gemessen: Laufwerk und + # MakeMKV sind in Ordnung. makemkvcon unter Linux ruft die + # Disc-Schlüssel schlicht nie ab — die Windows-Version tut es + # (Meldung 3338). Hier stand vorher erst "Disc zu neu" und danach + # "der Schlüssel-Kanal ist tot"; beides war falsch und hat in die + # Irre geschickt. Herleitung im Kopf von makemkv_daten.py. + speicher = makemkv_daten.schluesselspeicher_status() + anzahl = speicher.get("schluessel", 0) ergebnis["error"] += ( " — Klartext: Laufwerk und Rippy sind in Ordnung, MakeMKV " - "liest die Disc. Es kennt nur den Schlüssel dieser Pressung " - "nicht und holt ihn auch nicht mehr online nach — MakeMKVs " - "Schlüssel-Kanal liefert nichts mehr (am 25.07.2026 im " - "Worker nachgemessen). Abhilfe: eine KEYDB.cfg unter " - "Einstellungen → System hochladen; sie wirkt ab dem nächsten " - "Rip. " + "liest die Disc. Es fehlt nur der Schlüssel dieser Pressung. " + "Der Grund: makemkvcon holt Schlüssel unter Linux nie selbst " + "nach — die Windows-Version schon. " + ( - "Aktuell liegt dort keine KEYDB.cfg." - if not keydb.get("vorhanden") - else "Es liegt bereits eine KEYDB.cfg dort — sie kennt " - "diese Pressung offenbar nicht; eine neuere Fassung " - "kann helfen." + "Dieser Worker kennt aktuell GAR KEINEN Disc-Schlüssel. " + if not anzahl + else f"Dieser Worker kennt {anzahl} Disc-Schlüssel, " + "diese Pressung ist nicht dabei. " ) - + " Den AACS-Dump dieser Disc bewahrt Rippy jetzt dauerhaft " - "auf; er steht unter Einstellungen → System zum Download " - "bereit (für die Einreichung im MakeMKV-Forum, Bereich " - "'Ultra HD Blu-ray')." + + "Abhilfe: MakeMKV auf einem Windows-PC installieren, die " + "Disc dort einmal öffnen, dann die Datei _private_data.tar " + "aus dem MakeMKV-Datenverzeichnis unter Einstellungen → " + "System hochladen. Wirkt ab dem nächsten Rip. Klappt auch " + "das nicht, kennt MakeMKV die Pressung selbst nicht — dann " + "hilft nur eine KEYDB.cfg (ebenfalls dort hochladbar) oder " + "das Einreichen des AACS-Dumps im MakeMKV-Forum, Bereich " + "'Ultra HD Blu-ray'. Der Dump steht unter Einstellungen → " + "System zum Download bereit." ) elif disc_type == "uhd" and "Failed to open disc" in fehler_text: ergebnis["error"] += ( diff --git a/docker/worker/test_makemkv_daten_worker.py b/docker/worker/test_makemkv_daten_worker.py index 51f0cdc..b285cbd 100644 --- a/docker/worker/test_makemkv_daten_worker.py +++ b/docker/worker/test_makemkv_daten_worker.py @@ -42,6 +42,69 @@ ist_aacs_dump = _modul.ist_aacs_dump keydb_pruefen = _modul.keydb_pruefen settings_conf_zusammenfuehren = _modul.settings_conf_zusammenfuehren zaehle_disc_eintraege = _modul.zaehle_disc_eintraege +private_data_pruefen = _modul.private_data_pruefen +zaehle_schluessel = _modul.zaehle_schluessel + + +def _tar_mit(namen): + """Baut ein tar-Archiv im Speicher — so sieht MakeMKVs Schluesselspeicher aus. + + Echte Eintragsnamen aus dem Speicher der Windows-Installation vom + 25.07.2026: hkd_<8 Hex>.bin fuer die Schluessel, dazu Index-Dateien. + """ + import io + import tarfile + + puffer = io.BytesIO() + with tarfile.open(fileobj=puffer, mode="w") as archiv: + for name in namen: + eintrag = tarfile.TarInfo(name) + eintrag.size = 3 + archiv.addfile(eintrag, io.BytesIO(b"abc")) + return puffer.getvalue() + + +def test_zaehle_schluessel_zaehlt_nur_hkd_eintraege(): + # Nur hkd_*.bin sind Disc-Schluessel. Index- und sdf-Dateien gehoeren zum + # Speicher dazu, sind aber keine Schluessel — sonst meldete das UI + # "1 Schluessel vorhanden" fuer einen komplett leeren Vorrat. + voll = _tar_mit([ + "hkd_00000059.bin", + "hkd_0000005a.bin", + "sdf_000000a6.bin", + "--index-A2E950B3C3FC57DA9CB856DCAFBA5275F40423DB.bin", + ]) + assert zaehle_schluessel(voll) == 2 + + +def test_zaehle_schluessel_leerer_speicher_ist_null(): + # Genau dieser Zustand lag am 25.07.2026 auf der VM vor: ein Archiv mit + # ausschliesslich der Index-Datei. Jede unbekannte UHD-Disc scheitert dann. + leer = _tar_mit(["--index-4EF73C3560D489497ACE763962A7F07A4A1545C4.bin"]) + assert zaehle_schluessel(leer) == 0 + + +def test_zaehle_schluessel_bei_muell_kein_absturz(): + # Darf niemals werfen — die Zahl landet im Worker-Herzschlag. + assert zaehle_schluessel(b"") == 0 + assert zaehle_schluessel(b"das ist kein tar") == 0 + + +def test_private_data_pruefen_nimmt_echten_speicher_an(): + assert private_data_pruefen(_tar_mit(["hkd_00000059.bin"])) == "" + + +def test_private_data_pruefen_lehnt_leere_und_falsche_dateien_ab(): + assert "leer" in private_data_pruefen(b"") + assert "tar-Archiv" in private_data_pruefen(b"Fehlerseite") + + +def test_private_data_pruefen_lehnt_speicher_ohne_schluessel_ab(): + # Der teuerste Bedienfehler: den Speicher einer Installation hochladen, + # die selbst noch nie Schluessel geholt hat. Ohne diese Pruefung aendert + # sich nichts und niemand versteht, warum. + leer = _tar_mit(["--index-4EF73C3560D489497ACE763962A7F07A4A1545C4.bin"]) + assert "kein einziger Schluessel" in private_data_pruefen(leer) def test_zwillinge_sind_byteweise_identisch():