fix(uhd): 4K-UHD geloest - makemkvcon holt Schluessel unter Linux nie
Ampel / ampel (push) Successful in 28s
Ampel / ampel (push) Successful in 28s
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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).
|
||||
|
||||
+157
-24
@@ -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).
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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. <span className={fett}>Disc-Schlüssel für 4K-UHD kommen dagegen nicht
|
||||
aus einem Update</span>, sondern nur aus der Datei <code>KEYDB.cfg</code>, die du selbst
|
||||
unter Einstellungen → System hochlädst (mehr dazu unter „Häufige Fragen").
|
||||
aus einem Update</span> — die holt MakeMKV zur Laufzeit, und die Linux-Version tut das
|
||||
nie. Wie du sie trotzdem bekommst, steht unter „Häufige Fragen".
|
||||
</p>
|
||||
</Abschnitt>
|
||||
|
||||
@@ -161,30 +161,34 @@ export default function AnleitungPage() {
|
||||
Fingerabdruck. Nochmal rippen geht trotzdem — der Hinweis verhindert nur Versehen.
|
||||
</p>
|
||||
{/*
|
||||
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).
|
||||
*/}
|
||||
<p>
|
||||
<span className={fett}>4K-UHD schlägt fehl mit „volume key is unknown"?</span> 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: <span className={fett}>die Linux-Version
|
||||
von MakeMKV holt Disc-Schlüssel nie selbst aus dem Netz</span>. Die Windows-Version tut es.
|
||||
Ein MakeMKV-Update ändert daran nichts.
|
||||
</p>
|
||||
<p>
|
||||
Der einzige Weg, der heute funktioniert, ist eine Datei namens <code>KEYDB.cfg</code> —
|
||||
eine Textliste mit Disc-Schlüsseln, die du selbst mitbringst. Unter Einstellungen → System
|
||||
hochladen, sie wirkt ab dem nächsten Rip. <span className={fett}>Rippy liefert keine
|
||||
Schlüssel mit und lädt auch keine herunter</span> — Rippy stellt nur den Platz für deine
|
||||
Datei bereit und zeigt dir an, was dort liegt.
|
||||
<span className={fett}>Der Weg drumherum:</span> 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 <em>Preferences → General</em> das
|
||||
„MakeMKV data directory" nachschlagen und die Datei <code>_private_data.tar</code> 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.
|
||||
</p>
|
||||
<p>
|
||||
Der <span className={fett}>AACS-Dump</span> 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 <code>KEYDB.cfg</code> einträgst.
|
||||
Geht eine Pressung auch damit nicht auf, kennt MakeMKV sie selbst nicht. Dann bleiben zwei
|
||||
Dinge: eine <code>KEYDB.cfg</code> (ebenfalls dort hochladbar, der Notnagel), oder den
|
||||
<span className={fett}> AACS-Dump</span> im MakeMKV-Forum im Bereich „Ultra HD Blu-ray"
|
||||
einreichen — der bleibt jetzt erhalten und steht unter Einstellungen → System zum
|
||||
Herunterladen. <span className={fett}>Rippy liefert keine Schlüssel mit und lädt keine
|
||||
herunter</span> — es verwaltet nur, was du selbst mitbringst.
|
||||
</p>
|
||||
<p>
|
||||
<span className={fett}>„Neu komprimieren" fehlt bei einem Fehl-Job?</span> Der Knopf
|
||||
|
||||
@@ -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<AacsDump[]>([])
|
||||
const keydbInput = useRef<HTMLInputElement>(null)
|
||||
const [keystore, setKeystore] = useState<KeystoreStatus | null>(null)
|
||||
const [keystoreBusy, setKeystoreBusy] = useState(false)
|
||||
const keystoreInput = useRef<HTMLInputElement>(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}
|
||||
</span>
|
||||
)}
|
||||
{/* 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' && (
|
||||
<span className="text-xs px-2.5 py-0.5 rounded-md font-medium bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30">
|
||||
KEYDB.cfg vorhanden
|
||||
{w.info.schluessel} Disc-Schlüssel
|
||||
</span>
|
||||
)}
|
||||
{w.info?.keydb === 'nein' && (
|
||||
{w.info?.schluessel === '0' && (
|
||||
<span className="text-xs px-2.5 py-0.5 rounded-md font-medium bg-amber-500/15 text-amber-600 dark:text-amber-400 border border-amber-500/30">
|
||||
keine KEYDB.cfg
|
||||
keine Disc-Schlüssel — 4K-UHD scheitert
|
||||
</span>
|
||||
)}
|
||||
{w.info?.keydb === 'unbekannt' && (
|
||||
{w.info?.keydb === 'ja' && (
|
||||
<span className="text-xs px-2.5 py-0.5 rounded-md font-medium bg-slate-200 dark:bg-slate-800 text-slate-500 dark:text-slate-400 border border-slate-300 dark:border-slate-700">
|
||||
KEYDB.cfg unbekannt
|
||||
+ KEYDB.cfg
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -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.
|
||||
*/}
|
||||
<p className="text-xs mt-3 pt-3 border-t border-slate-200/60 dark:border-slate-800 text-slate-500 dark:text-slate-400">
|
||||
<strong className="text-slate-700 dark:text-slate-300">MakeMKV</strong> lässt sich aktuell halten
|
||||
(Update-Check unten; Version über <code>MAKEMKV_VERSION</code> + Rebuild) — neue Versionen bringen
|
||||
vor allem Laufwerks-Unterstützung und Fehlerbehebungen. <strong>Disc-Schlüssel für neue
|
||||
4K-UHD-Pressungen kommen dagegen NICHT aus einem Update</strong>, sondern nur aus der KEYDB.cfg
|
||||
im Block darunter.
|
||||
vor allem Laufwerks-Unterstützung und Fehlerbehebungen. <strong>Disc-Schlüssel für 4K-UHD kommen
|
||||
NICHT aus einem Update</strong> — die holt MakeMKV zur Laufzeit, und die Linux-Version tut das
|
||||
nie. Deshalb der Block „Disc-Schlüssel für 4K-UHD" weiter unten.
|
||||
{' '}<strong className="text-slate-700 dark:text-slate-300">HandBrake</strong> im eingebauten
|
||||
Docker-Worker ist bewusst die stabile <strong>Debian-Version</strong> — für die Kompression völlig
|
||||
ausreichend und wird <strong>nicht separat aktualisiert</strong>. 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.
|
||||
*/}
|
||||
<div className="p-4 rounded-xl border border-slate-200/80 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-950/80 space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm font-semibold text-slate-900 dark:text-slate-200 flex items-center gap-2">
|
||||
<Database size={16} className="text-amber-500" />
|
||||
Disc-Schlüssel für 4K-UHD
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="file"
|
||||
className="hidden"
|
||||
ref={keystoreInput}
|
||||
accept=".tar"
|
||||
onChange={(e) => {
|
||||
const datei = e.target.files?.[0]
|
||||
e.target.value = ''
|
||||
if (datei) keystoreHochladen(datei)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="amber"
|
||||
size="sm"
|
||||
onClick={() => keystoreInput.current?.click()}
|
||||
disabled={keystoreBusy}
|
||||
>
|
||||
<Upload size={14} />
|
||||
{keystoreBusy ? 'Übernehme…' : '_private_data.tar übernehmen'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{keystore?.vorhanden && keystore.schluessel > 0 ? (
|
||||
<div className="p-3 rounded-lg text-sm bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30">
|
||||
<p className="font-semibold">{keystore.schluessel} Disc-Schlüssel vorhanden.</p>
|
||||
<p className="text-xs mt-1">
|
||||
{bytesLesbar(keystore.groesse_bytes)} · zuletzt geändert {zeitLesbar(keystore.geaendert)}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-3 rounded-lg text-sm bg-amber-500/15 text-amber-600 dark:text-amber-400 border border-amber-500/30">
|
||||
<p className="font-semibold">Kein einziger Disc-Schlüssel vorhanden.</p>
|
||||
<p className="text-xs mt-1">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
<strong className="text-slate-700 dark:text-slate-300">Warum das nötig ist:</strong> MakeMKV
|
||||
holt sich diese Schlüssel eigentlich selbst aus dem Netz. Die <strong>Linux-Version tut das
|
||||
nicht</strong> — 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.
|
||||
</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
<strong className="text-slate-700 dark:text-slate-300">So füllst du den Vorrat:</strong> 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 <em>Preferences → General</em>
|
||||
das „MakeMKV data directory" nachschlagen, die Datei <code>_private_data.tar</code> daraus hier
|
||||
hochladen — fertig. Für neue Discs von Zeit zu Zeit wiederholen.
|
||||
</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Das ist der Zwischenspeicher <strong className="text-slate-700 dark:text-slate-300">deiner
|
||||
eigenen</strong> MakeMKV-Installation, über MakeMKVs offiziellen Weg mit deiner eigenen Lizenz
|
||||
geholt. Rippy liefert keine Schlüssel mit und lädt keine herunter.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/*
|
||||
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.
|
||||
*/}
|
||||
<div className="p-4 rounded-xl border border-slate-200/80 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-950/80 space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm font-semibold text-slate-900 dark:text-slate-200 flex items-center gap-2">
|
||||
<KeyRound size={16} className="text-amber-500" />
|
||||
MakeMKV-Schlüssel (KEYDB.cfg)
|
||||
KEYDB.cfg (Notnagel)
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
{/*
|
||||
@@ -834,20 +944,20 @@ export default function SettingsPage() {
|
||||
<p className="text-xs mt-1 font-mono opacity-80">{keydb.pfad}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-3 rounded-lg text-sm bg-amber-500/15 text-amber-600 dark:text-amber-400 border border-amber-500/30">
|
||||
<p className="font-semibold">Es liegt keine KEYDB.cfg bereit.</p>
|
||||
<div className="p-3 rounded-lg text-sm bg-slate-200 dark:bg-slate-800 text-slate-500 dark:text-slate-400 border border-slate-300 dark:border-slate-700">
|
||||
<p className="font-semibold">Keine KEYDB.cfg hinterlegt.</p>
|
||||
<p className="text-xs mt-1">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Die <strong className="text-slate-700 dark:text-slate-300">KEYDB.cfg</strong> 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 <strong className="text-slate-700 dark:text-slate-300">
|
||||
Notnagel</strong> 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.
|
||||
</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
<strong className="text-slate-700 dark:text-slate-300">Wichtig:</strong> Rippy liefert keine
|
||||
@@ -926,9 +1036,9 @@ export default function SettingsPage() {
|
||||
<p className="text-xs mt-1">
|
||||
⚠️ Update verfügbar — in der .env <code>MAKEMKV_VERSION={updates.makemkv.verfuegbar}</code> setzen,
|
||||
dann auf der Rippy-Maschine <code>docker compose build worker && docker compose up -d worker</code>.
|
||||
{/* 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
|
||||
<strong> keine Disc-Schlüssel</strong>: die kommen ausschließlich aus deiner KEYDB.cfg.
|
||||
<strong> keine Disc-Schlüssel</strong>: die kommen aus dem Schlüsselspeicher.
|
||||
</p>
|
||||
)
|
||||
: <span className="text-xs ml-1 text-emerald-600 dark:text-emerald-400">✓ aktuell</span>}
|
||||
|
||||
@@ -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
|
||||
|
||||
+157
-24
@@ -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).
|
||||
|
||||
|
||||
+24
-23
@@ -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"] += (
|
||||
|
||||
@@ -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"<html>Fehlerseite</html>")
|
||||
|
||||
|
||||
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():
|
||||
|
||||
Reference in New Issue
Block a user