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():