feat(uhd): KEYDB.cfg-Unterstuetzung - MakeMKVs Schluessel-Kanal liefert nichts mehr
Ampel / ampel (push) Successful in 28s
Ampel / ampel (push) Successful in 28s
4K-UHD scheiterte an "The volume key is unknown for this disc". Am 25.07.2026
im Worker-Container nachgemessen: Laufwerk und MakeMKV sind in Ordnung
(LibreDrive v06.3 / Meldung 1011, Disc wird gelesen, AACS-Dump geschrieben) -
MakeMKV versucht gar nicht erst, online einen Schluessel zu holen. Belege:
_private_data.tar enthaelt nur die Index-Datei und KEINE hkd_*.bin; auch mit
geloeschter update.conf (Meldung 5074 belegt den Web-Kontakt) und mit
app_UpdateEnable="1" kam keiner; hkdata.fairuse.org und hkdata.crabdance.com
loesen weltweit nicht mehr auf (NXDOMAIN gegen Fritz!Box, 8.8.8.8, 1.1.1.1).
Betroffen war Akira UHD (MKB v76, Pressung Dez. 2020) - also gerade KEINE
Neuerscheinung. Der bisherige Fehlertext ("Disc neuer als die
Schluessel-Datenbank, mit einem der naechsten Updates rippbar") war falsch.
Einziger heute funktionierender Weg ist eine vom Nutzer selbst mitgebrachte
KEYDB.cfg. Rippy liefert KEINE Schluessel mit, laedt keine herunter und
verteilt keine - es stellt nur den Platz bereit und zeigt an, was dort liegt.
- Datenverzeichnis persistent gemountet (MAKEMKV_DATA_HOST, Default
/srv/rippy/makemkv): KEYDB.cfg und AACS-Dumps ueberleben jeden Rebuild.
Vorher loeschte jeder "up -d --build" beides - inklusive des Dumps, auf den
die Fehlermeldung selbst verwies.
- entrypoint.sh und tasks.py schreiben settings.conf ergaenzend statt
zerstoerend. Der entrypoint bricht bei nicht beschreibbarem Verzeichnis
nicht mehr ab - mit "restart: unless-stopped" waere das ein Crashloop
gewesen, in dem auch reines DVD-Rippen tot ist.
- Neues Zwillings-Modul makemkv_daten.py (docker/api + docker/worker,
byteweise identisch; test_zwillinge_sind_byteweise_identisch wacht darueber
und wurde durch absichtliches Verstellen als wirksam nachgewiesen).
- API: GET/POST/DELETE /system/keydb, GET /system/aacs-dumps(/{dateiname}).
JSON-Body statt Multipart - python-multipart ist bewusst nicht installiert
und wuerde die API beim Import toeten. nginx client_max_body_size 64m,
sonst scheitert der Upload mit 413, bevor die API ihn sieht.
- UI (Einstellungen -> System): Status, Hochladen per Datei-Dialog, Entfernen,
Dump-Download, KEYDB-Plakette je Worker (nur wo das Verzeichnis wirklich
gemountet ist - ein Remote-Transcode-Worker truege sonst eine Warnung,
die ihn nichts angeht).
- parse_msg() + log_cb: MakeMKV-Meldungen landen im Rippy-Log (gedrosselt:
Code 1003 raus, keine Wiederholungen, max. 40 je Rip). Nebenbei behoben:
der alte Parser (split(",", 4)[3]) schnitt jede Meldung am ersten Komma ab.
- Fuenf Stellen richtiggestellt, die behaupteten, MakeMKV-Updates braechten
die neueste Disc-Schluessel-Datenbank mit (UI, Anleitung, README,
Worker-Dockerfile, makemkv_key.py).
NICHT bewiesen: ein erfolgreicher UHD-Rip - es lag keine KEYDB.cfg mit dem
Akira-Schluessel vor. Belegt sind der Befund und die neue Mechanik. So steht
es auch im SAVEPOINT und in der ROADMAP.
Quellen (AGENTS Regel D):
- Datenverzeichnis + Dateiname GROSS/case-sensitiv:
https://forum.makemkv.com/forum/viewtopic.php?t=30636
- hkd_*.bin in _private_data.tar:
https://forum.makemkv.com/forum/viewtopic.php?t=32675
- headless settings.conf / app_UpdateEnable:
https://forum.makemkv.com/forum/viewtopic.php?t=20364
- KEYDB.cfg-Zeilenformat (libaacs):
https://github.com/ShiftMediaProject/libaacs/blob/master/KEYDB.cfg
- MSG-/PRGV-Format: https://www.makemkv.com/developers/usage.txt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Save, Disc, Cpu, Database, Globe, AlertCircle, CheckCircle, HardDrive, Wrench, Send, Tv } from 'lucide-react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { Save, Disc, Cpu, Database, Globe, AlertCircle, CheckCircle, HardDrive, Wrench, Send, Tv, KeyRound, Upload, Trash2, Download } from 'lucide-react'
|
||||
import { api } from '../lib/api'
|
||||
import { useToast } from '../context/ToastContext'
|
||||
import StorageMounts from '../components/StorageMounts'
|
||||
@@ -62,7 +62,26 @@ type SettingsTab = 'ripping' | 'verarbeitung' | 'worker' | 'speicherziele' | 'ap
|
||||
interface WorkerInfo {
|
||||
name: string
|
||||
encoders: string[]
|
||||
info?: { makemkv?: string, handbrake?: string, makemkv_key?: string }
|
||||
// keydb: "ja" | "nein" | "unbekannt" — sagt, ob DIESER Worker eine KEYDB.cfg
|
||||
// in seinem MakeMKV-Datenverzeichnis sieht. Nur der Worker, der wirklich
|
||||
// rippt, zaehlt, deshalb steht die Angabe pro Worker und nicht global.
|
||||
info?: { makemkv?: string, handbrake?: string, makemkv_key?: string, keydb?: string }
|
||||
}
|
||||
|
||||
// Antwort von GET/POST/DELETE /system/keydb (Feldnamen exakt wie die API sie liefert).
|
||||
interface KeydbStatus {
|
||||
vorhanden: boolean
|
||||
pfad: string
|
||||
groesse_bytes: number
|
||||
eintraege: number
|
||||
geaendert: string
|
||||
}
|
||||
|
||||
// Ein AACS-Dump aus GET /system/aacs-dumps.
|
||||
interface AacsDump {
|
||||
name: string
|
||||
groesse_bytes: number
|
||||
geaendert: string
|
||||
}
|
||||
|
||||
interface SystemInfo {
|
||||
@@ -73,6 +92,24 @@ interface SystemInfo {
|
||||
webhook_gesetzt: boolean
|
||||
}
|
||||
|
||||
// Byte-Zahl menschenlesbar — eine echte KEYDB.cfg ist mehrere MB gross.
|
||||
function bytesLesbar(bytes: number): string {
|
||||
if (!bytes) return '0 B'
|
||||
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`
|
||||
return `${bytes} B`
|
||||
}
|
||||
|
||||
// Die API liefert ISO-8601 in UTC (oder einen leeren String). Ohne Zonen-Kennung
|
||||
// wuerde der Browser den Zeitstempel als Ortszeit lesen und die Uhrzeit um den
|
||||
// Zonen-Versatz verschieben — deshalb notfalls ein Z anhaengen.
|
||||
function zeitLesbar(iso: string): string {
|
||||
if (!iso) return 'unbekannt'
|
||||
const mitZone = /[Zz]$|[+-]\d{2}:?\d{2}$/.test(iso) ? iso : `${iso}Z`
|
||||
const d = new Date(mitZone)
|
||||
return isNaN(d.getTime()) ? 'unbekannt' : d.toLocaleString('de-DE')
|
||||
}
|
||||
|
||||
export default function SettingsPage() {
|
||||
const [settings, setSettings] = useState<SettingsState>(defaultSettings)
|
||||
const [activeTab, setActiveTab] = useState<SettingsTab>('ripping')
|
||||
@@ -86,6 +123,13 @@ export default function SettingsPage() {
|
||||
const [quellenBusy, setQuellenBusy] = useState(false)
|
||||
const [updates, setUpdates] = useState<Record<string, { installiert?: string, verfuegbar?: string, update?: boolean }> | null>(null)
|
||||
const [updatesBusy, setUpdatesBusy] = useState(false)
|
||||
// KEYDB.cfg und AACS-Dumps sind DATEIEN im MakeMKV-Datenverzeichnis, keine
|
||||
// Einstellungen — deshalb bewusst NICHT in SettingsState: der globale
|
||||
// Speichern-Knopf postet dieses Objekt komplett und wuerde sie mitschleifen.
|
||||
const [keydb, setKeydb] = useState<KeydbStatus | null>(null)
|
||||
const [keydbBusy, setKeydbBusy] = useState(false)
|
||||
const [dumps, setDumps] = useState<AacsDump[]>([])
|
||||
const keydbInput = useRef<HTMLInputElement>(null)
|
||||
|
||||
const { toast } = useToast()
|
||||
|
||||
@@ -106,6 +150,49 @@ export default function SettingsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// Status der KEYDB.cfg + Liste der AACS-Dumps frisch holen. Wird beim Laden
|
||||
// der Seite und nach jeder Aktion aufgerufen — die API ist die Wahrheit,
|
||||
// nicht das, was wir gerade hochgeschickt haben.
|
||||
const keydbLaden = () => {
|
||||
api.get('/system/keydb').then(r => setKeydb(r.data)).catch(() => setKeydb(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
|
||||
// widerspraeche die Kachel nach einem Upload sichtbar der Erfolgsmeldung.
|
||||
// Ganz sofort ist sie trotzdem nicht: der Worker meldet erst beim
|
||||
// naechsten Herzschlag neu. Genau so steht es auch im Erklaertext.
|
||||
api.get('/capabilities').then(r => setWorkers(r.data.workers || [])).catch(() => setWorkers([]))
|
||||
}
|
||||
|
||||
const keydbHochladen = async (datei: File) => {
|
||||
setKeydbBusy(true)
|
||||
try {
|
||||
// Bewusst als JSON-Text und nicht als Multipart-Upload: der API fehlt
|
||||
// python-multipart, ein File()-Endpunkt wuerde sie beim Import killen.
|
||||
const inhalt = await datei.text()
|
||||
await api.post('/system/keydb', { inhalt })
|
||||
keydbLaden()
|
||||
toast('success', 'KEYDB.cfg gespeichert — sie wirkt ab dem nächsten Rip.')
|
||||
} catch (e: any) {
|
||||
toast('error', e?.response?.data?.detail || 'Hochladen fehlgeschlagen — ist das wirklich eine KEYDB.cfg, und läuft die API?')
|
||||
} finally {
|
||||
setKeydbBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
const keydbEntfernen = async () => {
|
||||
setKeydbBusy(true)
|
||||
try {
|
||||
await api.delete('/system/keydb')
|
||||
keydbLaden()
|
||||
toast('success', 'KEYDB.cfg entfernt — Rippy nutzt jetzt keine Schlüsseldatei mehr.')
|
||||
} catch (e: any) {
|
||||
toast('error', e?.response?.data?.detail || 'Entfernen fehlgeschlagen — läuft die API?')
|
||||
} finally {
|
||||
setKeydbBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
const quellenPruefen = async () => {
|
||||
setQuellenBusy(true)
|
||||
try {
|
||||
@@ -131,6 +218,12 @@ export default function SettingsPage() {
|
||||
api.get('/system/info')
|
||||
.then(r => setSystemInfo(r.data))
|
||||
.catch(() => setSystemInfo(null))
|
||||
api.get('/system/keydb')
|
||||
.then(r => setKeydb(r.data))
|
||||
.catch(() => setKeydb(null))
|
||||
api.get('/system/aacs-dumps')
|
||||
.then(r => setDumps(r.data?.dumps || []))
|
||||
.catch(() => setDumps([]))
|
||||
}, [])
|
||||
|
||||
const webhookTesten = async () => {
|
||||
@@ -633,13 +726,40 @@ export default function SettingsPage() {
|
||||
HandBrake {w.info.handbrake}
|
||||
</span>
|
||||
)}
|
||||
{/* Nur das Verzeichnis des rippenden Workers zaehlt — deshalb je Worker. */}
|
||||
{w.info?.keydb === 'ja' && (
|
||||
<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
|
||||
</span>
|
||||
)}
|
||||
{w.info?.keydb === 'nein' && (
|
||||
<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
|
||||
</span>
|
||||
)}
|
||||
{w.info?.keydb === 'unbekannt' && (
|
||||
<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
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
{/*
|
||||
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.
|
||||
*/}
|
||||
<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) — wichtig wegen der
|
||||
Disc-Schlüssel-Datenbank.
|
||||
(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.
|
||||
{' '}<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
|
||||
@@ -655,6 +775,140 @@ export default function SettingsPage() {
|
||||
placeholder="T-… (Forum-Thread „MakeMKV is free while in beta”)"
|
||||
/>
|
||||
|
||||
{/*
|
||||
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.
|
||||
*/}
|
||||
<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)
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
{/*
|
||||
Versteckter Datei-Dialog: der Inhalt wird im Browser gelesen und als
|
||||
JSON gepostet. Kein Multipart — der API fehlt python-multipart.
|
||||
*/}
|
||||
<input
|
||||
type="file"
|
||||
className="hidden"
|
||||
ref={keydbInput}
|
||||
accept=".cfg,text/plain"
|
||||
onChange={(e) => {
|
||||
const datei = e.target.files?.[0]
|
||||
// Wert leeren, damit dieselbe Datei erneut gewählt werden kann.
|
||||
e.target.value = ''
|
||||
if (datei) keydbHochladen(datei)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="amber"
|
||||
size="sm"
|
||||
onClick={() => keydbInput.current?.click()}
|
||||
disabled={keydbBusy}
|
||||
>
|
||||
<Upload size={14} />
|
||||
{keydbBusy ? 'Arbeite…' : 'KEYDB.cfg hochladen'}
|
||||
</Button>
|
||||
{keydb?.vorhanden && (
|
||||
<Button variant="danger" size="sm" onClick={keydbEntfernen} disabled={keydbBusy}>
|
||||
<Trash2 size={14} />
|
||||
Entfernen
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{keydb?.vorhanden ? (
|
||||
<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">Eine KEYDB.cfg liegt bereit.</p>
|
||||
<p className="text-xs mt-1">
|
||||
{bytesLesbar(keydb.groesse_bytes)} · {keydb.eintraege} Zeilen mit Disc-Kennung ·
|
||||
zuletzt geändert {zeitLesbar(keydb.geaendert)}
|
||||
</p>
|
||||
<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>
|
||||
<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.
|
||||
</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.
|
||||
</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
|
||||
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. Die Zahl oben ist
|
||||
genau das: die gezählten Zeilen mit einer Disc-Kennung in deiner Datei — keine von MakeMKV
|
||||
bestätigte Anzahl brauchbarer Schlüssel.
|
||||
</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Eine hochgeladene Datei ersetzt die bisherige und wirkt
|
||||
<strong className="text-slate-700 dark:text-slate-300"> ab dem nächsten Rip</strong> — laufende
|
||||
Jobs bleiben unberührt, ein Neustart ist nicht nötig. Die Plakette am Worker weiter oben
|
||||
folgt erst mit dessen nächstem Herzschlag (etwa eine Minute) — dieser Kasten hier ist sofort
|
||||
aktuell.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/*
|
||||
AACS-Dumps: MakeMKV legt sie bei einer unbekannten UHD-Disc ab (Meldung 3332).
|
||||
Seit das Datenverzeichnis persistent gemountet ist, ueberleben sie den
|
||||
Container-Neustart — vorher waren sie nach jedem Rip weg.
|
||||
*/}
|
||||
<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">AACS-Dumps</p>
|
||||
<Button variant="secondary" size="sm" onClick={keydbLaden}>
|
||||
Liste aktualisieren
|
||||
</Button>
|
||||
</div>
|
||||
{dumps.length === 0 ? (
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Noch kein Dump vorhanden. MakeMKV legt hier automatisch einen ab, sobald eine 4K-UHD-Disc
|
||||
an einem unbekannten Schlüssel scheitert.
|
||||
</p>
|
||||
) : (
|
||||
<div className="space-y-1.5">
|
||||
{dumps.map(d => (
|
||||
<a
|
||||
key={d.name}
|
||||
href={`/api/system/aacs-dumps/${encodeURIComponent(d.name)}`}
|
||||
download
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors text-amber-600 dark:text-amber-300 hover:bg-slate-100 dark:hover:bg-slate-800"
|
||||
>
|
||||
<Download size={14} className="flex-shrink-0" />
|
||||
<span className="truncate min-w-0 font-mono">{d.name}</span>
|
||||
<span className="ml-auto text-xs flex-shrink-0 text-slate-500 dark:text-slate-400 font-mono">
|
||||
{bytesLesbar(d.groesse_bytes)} · {zeitLesbar(d.geaendert)}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Ein AACS-Dump ist das, was das Laufwerk von der Disc gelesen hat, bevor der Schlüssel fehlte.
|
||||
Er enthält keinen Schlüssel und nützt dir allein nichts — aber du kannst ihn herunterladen und
|
||||
im MakeMKV-Forum im Bereich <strong className="text-slate-700 dark:text-slate-300">Ultra HD
|
||||
Blu-ray</strong> einreichen. Dort können Leute daraus den Schlüssel für deine Pressung ermitteln;
|
||||
den trägst du dann in deine KEYDB.cfg ein.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<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">Update-Check</p>
|
||||
@@ -672,7 +926,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>.
|
||||
Neue Versionen bringen auch die neueste Disc-Schlüssel-Datenbank mit.
|
||||
{/* 25.07.2026 richtiggestellt: ein Update bringt KEINE Schluessel — die kommen nur aus der KEYDB.cfg. */}
|
||||
Neue Versionen bringen Laufwerks-Unterstützung und Fehlerbehebungen — aber
|
||||
<strong> keine Disc-Schlüssel</strong>: die kommen ausschließlich aus deiner KEYDB.cfg.
|
||||
</p>
|
||||
)
|
||||
: <span className="text-xs ml-1 text-emerald-600 dark:text-emerald-400">✓ aktuell</span>}
|
||||
|
||||
Reference in New Issue
Block a user