feat(v5): MakeMKV-Selbst-Update (§ 9) und Kino-Look fürs Fenster
Ampel / ampel (push) Successful in 1m34s
Ampel / ampel (push) Successful in 1m34s
Update-Strecke: Quellenkette (Hersteller 525 → Forum → Archiv, höchste gewinnt, 31.08. nachgemessen), MZ- + Versions-Ressourcen-Prüfung (GuinpinSoft inc, gemessen), Download in .neu, Start übers Haupt (shell/UAC — Installer hängt bewusst NICHT an der Leine), Warte-Poll bis die EXE-Version wechselt, dann Schlüssel neu prüfen. Ehrlicher Zweig: installierte == neueste Fassung → kein sinnloser Download. Fenster: Laufwerks-Kachel als Bühne (TMDb-Backdrop, Poster, Beschreibung, Phasen-Label, Restzeit, aufklappbares Protokoll), Bibliothek als Poster-Regal (DB-Schema 3: poster_pfad, Migration), Schlüssel-Karte mit Update-Knopf und Beschaffungs-Balken, MakeMKV-Version als Badge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5622d8e47d
commit
d5ea48cd1e
@@ -113,6 +113,8 @@ async function discErmitteln(id: string, geraetepfad: string, groesseBytes: numb
|
||||
confidence: zuordnung.confidence,
|
||||
quelle: zuordnung.meta.quelle,
|
||||
posterPfad: zuordnung.meta.posterPfad,
|
||||
backdropPfad: zuordnung.meta.backdropPfad,
|
||||
beschreibung: zuordnung.meta.beschreibung,
|
||||
// § 6.6: Rippy erkennt beim Einlegen, wenn eine Disc schon einmal
|
||||
// durchgelaufen ist — und fragt nach, statt stumm zu doppeln.
|
||||
schonGerippt: db?.bibliothekSchonGerippt(fingerprint) ?? null,
|
||||
@@ -182,6 +184,7 @@ async function zuordnungSetzen(id: string, vorschlag: MetaVorschlag): Promise<vo
|
||||
jahr: jahrAus(vorschlag.typ === 'movie' ? details?.release_date : details?.first_air_date) ?? vorschlag.jahr,
|
||||
beschreibung: details?.overview ?? '',
|
||||
posterPfad: details?.poster_path ?? vorschlag.posterPfad,
|
||||
backdropPfad: details?.backdrop_path ?? '',
|
||||
laufzeitMinuten: details?.runtime ?? 0,
|
||||
genres: (details?.genres ?? []).map((g) => g.name),
|
||||
quelle: 'tmdb',
|
||||
@@ -197,6 +200,8 @@ async function zuordnungSetzen(id: string, vorschlag: MetaVorschlag): Promise<vo
|
||||
confidence: 1,
|
||||
quelle: 'deine Wahl',
|
||||
posterPfad: zuordnung.meta.posterPfad,
|
||||
backdropPfad: zuordnung.meta.backdropPfad,
|
||||
beschreibung: zuordnung.meta.beschreibung,
|
||||
schonGerippt: db?.bibliothekSchonGerippt(discFingerprints.get(id) ?? '') ?? null,
|
||||
},
|
||||
})
|
||||
@@ -231,6 +236,8 @@ const laufwerkeBereit: Promise<void> = (async () => {
|
||||
confidence: 0,
|
||||
quelle: '',
|
||||
posterPfad: '',
|
||||
backdropPfad: '',
|
||||
beschreibung: '',
|
||||
schonGerippt: null,
|
||||
},
|
||||
})
|
||||
@@ -385,6 +392,113 @@ async function schluesselLauf(): Promise<void> {
|
||||
// Täglich neu prüfen (§ 9.1) — ohne den Prozess-Exit aufzuhalten.
|
||||
setInterval(() => void schluesselLauf(), 24 * 60 * 60 * 1000).unref()
|
||||
|
||||
// ── MakeMKV-Update (§ 9): holen, prüfen, installieren lassen ────────────
|
||||
// Der Kern lädt und PRÜFT die Datei; STARTEN kann sie nur das Haupt
|
||||
// (shell → UAC-Abfrage; der erhöhte Installer hängt dadurch nicht an der
|
||||
// Prozess-Leine und überlebt ein geschlossenes Rippy).
|
||||
let beschaffungLaeuft = false
|
||||
let installerAntwort: ((fehler: string | null) => void) | null = null
|
||||
|
||||
function beschaffungMelden(text: string, anteil: number | null, laeuft: boolean, fehler = false): void {
|
||||
anFenster({ art: 'beschaffung-status', stand: { werkzeug: 'makemkv', laeuft, text, anteil, fehler } })
|
||||
}
|
||||
|
||||
async function makemkvUpdateLauf(): Promise<void> {
|
||||
if (beschaffungLaeuft) {
|
||||
beschaffungMelden('Ein MakeMKV-Update läuft bereits.', null, true)
|
||||
return
|
||||
}
|
||||
beschaffungLaeuft = true
|
||||
try {
|
||||
const { istNeuer, makemkvNeuesteVersion, makemkvInstallerHolen, versionsangaben } = await import(
|
||||
'./werkzeuge/beschaffen'
|
||||
)
|
||||
beschaffungMelden('Nach der neuesten MakeMKV-Fassung wird gesucht …', null, true)
|
||||
const neueste = await makemkvNeuesteVersion()
|
||||
if (neueste.length === 0) {
|
||||
beschaffungMelden(
|
||||
'Keine der Quellen konnte sagen, welche Fassung aktuell ist (Hersteller-Seite, Forum, Archiv). ' +
|
||||
'Ausweg: MakeMKV von Hand von makemkv.com laden und installieren; Rippy findet es danach von allein.',
|
||||
null,
|
||||
false,
|
||||
true,
|
||||
)
|
||||
beschaffungLaeuft = false
|
||||
return
|
||||
}
|
||||
const installiert = schluesselStand?.version ?? ''
|
||||
if (installiert.length > 0 && !istNeuer(neueste, installiert)) {
|
||||
// Ehrlich bleiben (31.08.2026 gemessen: 1.18.4 ist installiert UND
|
||||
// die neueste angekündigte — die Beta ist nur abgelaufen): Ein
|
||||
// Download derselben Fassung würde nichts lösen.
|
||||
beschaffungMelden(
|
||||
`MakeMKV ${installiert} ist bereits die neueste angekündigte Fassung. ` +
|
||||
'Sobald der Hersteller eine neuere veröffentlicht, holt dieser Knopf sie — ' +
|
||||
'bis dahin rippt der Beta-Modus weiter.',
|
||||
null,
|
||||
false,
|
||||
)
|
||||
beschaffungLaeuft = false
|
||||
return
|
||||
}
|
||||
// Merken, woran eine gelungene Installation zu erkennen ist: Die
|
||||
// Versions-Ressource der gefundenen EXE ändert sich (oder es gibt
|
||||
// erstmals eine).
|
||||
const alteExe = finden('makemkv', db?.einstellungLesen('werkzeug.makemkv') ?? '')
|
||||
const alteVersion = alteExe.length > 0 ? versionsangaben(alteExe).version : ''
|
||||
|
||||
const ergebnis = await makemkvInstallerHolen(neueste, (text, anteil) =>
|
||||
beschaffungMelden(text, anteil, true),
|
||||
)
|
||||
beschaffungMelden(`Geprüft (Quelle: ${ergebnis.quelle}) — der Installer wird gestartet …`, null, true)
|
||||
|
||||
const startFehler = await new Promise<string | null>((fertig) => {
|
||||
installerAntwort = fertig
|
||||
process.parentPort.postMessage({ art: 'installer-starten', pfad: ergebnis.pfad })
|
||||
// Falls das Haupt nie antwortet, bleibt der Lauf nicht ewig hängen.
|
||||
setTimeout(() => fertig('Keine Antwort vom Haupt-Prozess'), 30_000).unref()
|
||||
})
|
||||
installerAntwort = null
|
||||
if (startFehler !== null && startFehler.length > 0) {
|
||||
beschaffungMelden(`Der Installer wurde nicht gestartet: ${startFehler}`, null, false, true)
|
||||
beschaffungLaeuft = false
|
||||
return
|
||||
}
|
||||
beschaffungMelden(
|
||||
`Der MakeMKV-Installer ${ergebnis.version} läuft — bitte die Windows-Nachfrage bestätigen und durchklicken. ` +
|
||||
'Rippy merkt die fertige Installation von allein und prüft den Schlüssel neu.',
|
||||
null,
|
||||
true,
|
||||
)
|
||||
// Warten, bis die Installation durch ist: Die Versions-Ressource der
|
||||
// EXE ändert sich. Alle 15 s nachsehen, höchstens 20 Minuten.
|
||||
let runden = 0
|
||||
const zeiger = setInterval(() => {
|
||||
runden += 1
|
||||
const exe = finden('makemkv', db?.einstellungLesen('werkzeug.makemkv') ?? '')
|
||||
const jetztVersion = exe.length > 0 ? versionsangaben(exe).version : ''
|
||||
if (jetztVersion.length > 0 && jetztVersion !== alteVersion) {
|
||||
clearInterval(zeiger)
|
||||
beschaffungLaeuft = false
|
||||
beschaffungMelden(`MakeMKV ${jetztVersion} ist installiert — der Schlüssel wird neu geprüft.`, null, false)
|
||||
void schluesselLauf().then(() => werkzeugeSenden())
|
||||
} else if (runden >= 80) {
|
||||
clearInterval(zeiger)
|
||||
beschaffungLaeuft = false
|
||||
beschaffungMelden(
|
||||
'Die fertige Installation wurde nicht bemerkt — nach dem Durchklicken hilft „Schlüssel neu prüfen".',
|
||||
null,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}, 15_000)
|
||||
zeiger.unref()
|
||||
} catch (fehler) {
|
||||
beschaffungMelden(fehler instanceof Error ? fehler.message : String(fehler), null, false, true)
|
||||
beschaffungLaeuft = false
|
||||
}
|
||||
}
|
||||
|
||||
// Die gemessene Auskunft bleibt liegen — die Pipeline braucht sie für die
|
||||
// Preset-Empfehlung, auch wenn gerade kein Fenster offen ist.
|
||||
let werkzeugAuskunft: { presets: string[]; backends: string[] } = { presets: [], backends: [] }
|
||||
@@ -432,6 +546,11 @@ async function auswerfen(id: string): Promise<void> {
|
||||
|
||||
process.parentPort.on('message', (ereignis) => {
|
||||
const nachricht: unknown = ereignis.data
|
||||
if (istHauptNachricht(nachricht) && nachricht.art === 'installer-ergebnis') {
|
||||
installerAntwort?.(nachricht.fehler ?? '')
|
||||
installerAntwort = null
|
||||
return
|
||||
}
|
||||
if (istHauptNachricht(nachricht) && nachricht.art === 'fenster-port') {
|
||||
// Das Haupt reicht einen frischen Port zum Fenster durch. Ein neues
|
||||
// Fenster bringt einen neuen Port — der alte wird geschlossen.
|
||||
@@ -468,6 +587,10 @@ process.parentPort.on('message', (ereignis) => {
|
||||
void werkzeugeSenden()
|
||||
} else if (frage.art === 'bibliothek-laden') {
|
||||
anFenster({ art: 'bibliothek', eintraege: db?.bibliothekListe() ?? [] })
|
||||
} else if (frage.art === 'makemkv-update') {
|
||||
void makemkvUpdateLauf()
|
||||
} else if (frage.art === 'schluessel-pruefen') {
|
||||
void schluesselLauf().then(() => werkzeugeSenden())
|
||||
}
|
||||
})
|
||||
fensterPort.start()
|
||||
|
||||
Reference in New Issue
Block a user