From f449c4ee3498cfe4c86a6a6939f7256c0898362b Mon Sep 17 00:00:00 2001
From: Hitonabi
Date: Sat, 25 Jul 2026 11:18:09 +0200
Subject: [PATCH] fix(uhd): 4K-UHD geloest - makemkvcon holt Schluessel unter
Linux nie
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Richtigstellung des Vortags-Befunds. Dort stand, 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 zwar wirklich nicht mehr aufloesen, von MakeMKV
aber laengst nicht mehr benutzt werden. Aufgedeckt durch den Einwand des
Commanders, unter Windows ginge es sofort.
Gegenprobe mit demselben Laufwerk und derselben Disc (Akira UHD, MKB v76):
Linux (Worker) Windows
Verbindungen KEINE EINZIGE 185.84.108.20:443
Meldung 3338 nie "Downloading latest HK"
_private_data.tar 2048 B, 0 Keys 6,4 MB, 604 Keys
Disc volume key unknown TCOUNT:5, geht auf
Gegengeprueft mit leerem UND gefuelltem Speicher, mit und ohne --noscan,
mit dev:/dev/sr0 und disc:0, mit geloeschter update.conf. Linux fragt nie.
Die Meldungsvorlage "Downloading latest %1 to %2 ..." steckt sehr wohl im
Linux-Binary - sie loest nur nicht aus. Gleiches Symptom im MakeMKV-Forum,
seit Jahren offen (t=25782, t=34022). Der Dienst lebt; der Worker erreicht
185.84.108.20:443 sogar problemlos.
BEWIESEN: Nach Uebernahme des Windows-Schluesselspeichers oeffnet
makemkvcon auf der VM die Akira-UHD - "Operation successfully completed",
TCOUNT:5, fuenf Titel, identisch zum Windows-Ergebnis. Erster belegter
UHD-Disc-Zugriff auf der Rippy-Maschine.
- makemkv_daten.py (beide Zwillinge): zaehle_schluessel,
private_data_pruefen, schluesselspeicher_status, private_data_schreiben.
Die Pruefung lehnt einen Speicher OHNE hkd_*.bin ab - sonst laedt jemand
den leeren Vorrat einer frischen Installation hoch, nichts aendert sich,
und niemand versteht warum. Modulkopf komplett neu, inkl. der
Fehldiagnose als Warnung fuer spaeter.
- API: GET/POST /system/keystore. Der Rohkoerper der Anfrage IST die Datei
(binaer - JSON/Base64 waere Ballast, Multipart kann die API nicht).
Groessengrenze 64 MB = client_max_body_size in nginx.conf.
- UI: neuer Block "Disc-Schluessel fuer 4K-UHD" UEBER dem KEYDB-Block, mit
Schluessel-Anzahl, Upload und Anleitung fuer den Windows-Weg. KEYDB.cfg
ist jetzt als Notnagel beschriftet. Worker-Plakette zeigt die Anzahl;
0 heisst sichtbar "4K-UHD scheitert".
- tasks.py: UHD-Fehlertext sagt den Windows-Weg an und nennt die Anzahl
bekannter Schluessel dieses Workers.
- caps.py meldet schluessel je Worker.
- Alle Falschaussagen korrigiert: UI (3), Anleitung (2), README (3),
KONZEPT §8 + §10, Worker-Dockerfile, makemkv_key.py (dort stand "Den
AACS-Schluessel zieht MakeMKV via LibreDrive ohnehin selbst aus dem
Laufwerk" - gilt fuer Blu-ray, NICHT fuer UHD).
- SAVEPOINT v3.11, ROADMAP Etappe 18 (Etappe 17 mit Nachtrag), AGENTS.
Offen: voller UHD-Rip inkl. Transcode-E2E; und ob sich der Abruf unter
Linux doch anstossen laesst.
Quellen (AGENTS Regel D):
- Linux laedt keine Hashed Keys, gleiches Symptom:
https://forum.makemkv.com/forum/viewtopic.php?t=25782
https://forum.makemkv.com/forum/viewtopic.php?t=34022
- Schluessel als hkd_*.bin in _private_data.tar:
https://forum.makemkv.com/forum/viewtopic.php?t=32675
- Meldungsformat: https://www.makemkv.com/developers/usage.txt
Co-Authored-By: Claude Opus 5
---
AGENTS.md | 6 +-
KONZEPT.md | 14 +-
README.md | 85 ++++++----
ROADMAP.md | 68 ++++++++
SAVEPOINT.md | 65 +++++++-
docker/api/main.py | 57 +++++++
docker/api/makemkv_daten.py | 181 ++++++++++++++++++---
docker/api/test_api_smoke.py | 3 +
docker/ui/src/pages/Anleitung.tsx | 40 +++--
docker/ui/src/pages/Settings.tsx | 174 ++++++++++++++++----
docker/worker/caps.py | 7 +
docker/worker/makemkv_daten.py | 181 ++++++++++++++++++---
docker/worker/tasks.py | 47 +++---
docker/worker/test_makemkv_daten_worker.py | 63 +++++++
14 files changed, 828 insertions(+), 163 deletions(-)
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.
+ */}
+
+ 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.
*/}
{/*
@@ -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():