feat(v5): MakeMKV-Selbst-Update (§ 9) und Kino-Look fürs Fenster
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:
Hitonabi
2026-08-31 20:18:08 +02:00
co-authored by Claude Fable 5
parent 5622d8e47d
commit d5ea48cd1e
15 changed files with 1199 additions and 201 deletions
+24 -2
View File
@@ -8,10 +8,11 @@
// („Ein Fenster geht auf, der Kern läuft") maschinell — alle drei Prozesse,
// beide IPC-Wege und die Datenbank — und endet mit Code 0 (grün) oder 2.
// RIPPY_SMOKE_BILD=<pfad.png> legt zusätzlich einen Screenshot ab.
import { app, dialog, ipcMain, Notification, type BrowserWindow } from 'electron'
import { app, dialog, ipcMain, Notification, shell, type BrowserWindow } from 'electron'
import { writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { join, win32 } from 'node:path'
import type { HauptStatus, KernNachricht } from '../gemeinsam/nachrichten'
import { werkzeugOrdner } from '../kern/werkzeuge/katalog'
import { autostartAktiv, autostartSetzen } from './autostart'
import { fensterErstellen } from './fenster'
import { KernVerwaltung } from './kernstart'
@@ -84,6 +85,8 @@ function start(): void {
(text) => toast('Rippy-Update', text),
)
}
} else if (nachricht.art === 'installer-starten') {
void installerStarten(nachricht.pfad)
} else if (nachricht.art === 'disc-info' && nachricht.info.titel.length > 0 && !smokeModus) {
// Windows-Toast beim Erkennen (§ 7) — Klick holt das Fenster hoch.
toast(
@@ -131,6 +134,25 @@ function start(): void {
}
}
// § 9: Der Kern hat einen geprüften Installer abgelegt — gestartet wird
// er HIER über die Shell. Zwei Gründe: (1) MakeMKVs Installer fordert im
// Manifest Administratorrechte an — CreateProcess bricht dann mit
// ERROR_ELEVATION_REQUIRED ab, nur der Shell-Weg zeigt die UAC-Abfrage
// (beschaffen.py, am Commander-PC gemessen). (2) Die Erhöhung läuft über
// den AppInfo-Dienst, der Installer ist dadurch KEIN Kind von Rippy —
// er hängt nicht an der Prozess-Leine und überlebt ein Beenden.
async function installerStarten(pfad: string): Promise<void> {
// Nur, was der Kern selbst geladen und geprüft hat: eine .exe aus
// Rippys eigenem Downloads-Ordner.
const downloads = win32.join(werkzeugOrdner(), 'downloads') + '\\'
if (!pfad.startsWith(downloads) || !pfad.toLowerCase().endsWith('.exe')) {
kernVerwaltung.senden({ art: 'installer-ergebnis', fehler: `Pfad außerhalb des Downloads-Ordners: ${pfad}` })
return
}
const fehler = await shell.openPath(pfad)
kernVerwaltung.senden({ art: 'installer-ergebnis', fehler: fehler.length > 0 ? fehler : null })
}
function toast(titel: string, text: string): void {
try {
if (!Notification.isSupported()) return
+5
View File
@@ -87,6 +87,11 @@ export class KernVerwaltung {
webContents.postMessage('kern-port', null, [port2])
}
/** Eine Nachricht an den Kern (z. B. die Antwort auf 'installer-starten'). */
senden(nachricht: HauptNachricht): void {
this.kern?.postMessage(nachricht)
}
zustand(): KernZustand {
return {
laeuft: this.kern !== null,