feat(v5): Etappe W-6 — Setup, Selbst-Update, Erst-Einrichtung, Lizenzen
Ampel / ampel (push) Successful in 1m22s

electron-builder → NSIS: EIN RippySetup-<version>.exe, pro Benutzer,
ohne Adminrechte, eigenes Icon (PNG-basiertes ICO selbst gebaut).
extraResources: die MITGELIEFERTEN Werkzeuge (HandBrakeCLI GPL-2,
flac.exe MIT libFLAC.dll — die Ohne-DLL-Falle aus § 9) samt
Lizenztexten und Quellverweisen (bau/lizenzen, Entscheid 9); vendor/
liegt nicht im Git (74 MB), Befuellung steht in BAUEN.md. Der Kern
findet die mitgelieferten Werkzeuge ueber RIPPY_VENDOR (resourcesvendor) VOR allen anderen Suchwegen.

haupt/update.ts (§ 6.8): electron-updater gegen das oeffentliche Gitea
(festes Tag 'aktuell' als Rueckfallebene, Entscheid 6) — NUR https
(http wird ABGELEHNT; Regel-Tests), NIE waehrend eines Rips (der Haupt
kennt die aktiven Vorgaenge), Fehlschlaege still aber ablesbar
(letzte erfolgreiche Pruefung im Status), installiert beim naechsten
Start. haupt/autostart.ts: HKCU-Run ueber app.setLoginItemSettings,
Toggle in den Einstellungen. Erst-Einrichtung (§ 6.9) im Programm:
5 Schritte, NUR ein Fehler blockiert (kein Laufwerk = Warnung,
MakeMKV-Pflicht mit Klartext-Weg).

GEBAUT UND GEMESSEN (30.08.2026):
- dist-setup/RippySetup-5.0.0-w0.exe — 130,8 MB, SHA-256
  07D39D6BAB74A47C21AA53D847FB5A5DB6990AE9FA1CBC7BE814B51050883115,
  plus .blockmap.
- MESSUNG: Die Update-Auskunft heisst bei Vorab-Versionen nach dem
  KANAL (w0.yml) — erst ein Release ohne Suffix erzeugt latest.yml
  (steht jetzt in BAUEN.md).
- Das GEPACKTE Programm (win-unpacked, asar + resources) besteht den
  Smoke: SMOKE OK, und der Screenshot zeigt die Erst-Einrichtung —
  das Bild eines frischen Rechners.

Bewusst offen (SAVEPOINT): die automatische MakeMKV-Beschaffung
(beschaffen.ts — Download+Installer-Start braucht einen Live-Test);
das Setup NENNT den Weg klar. 185 Tests gruen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-30 19:03:40 +02:00
co-authored by Claude Fable 5
parent 2d9cef22b3
commit 9fa3df500d
21 changed files with 4319 additions and 8 deletions
+83
View File
@@ -0,0 +1,83 @@
// Selbst-Update (KONZEPT § 6.8) — electron-updater gegen die Releases im
// öffentlichen Gitea (Entscheid 6). Die vier Regeln:
// 1. NUR HTTPS — ohne Code-Signing (Entscheid 5) ist der Transportweg
// die einzige Absicherung; eine http://-Adresse wird ABGELEHNT.
// 2. NIE während eines Rips — weder laden noch installieren.
// 3. Ein Fehlschlag ist sichtbar, aber nicht laut: Der Zeitpunkt der
// letzten erfolgreichen Prüfung steht im Status.
// 4. Die laufende Version ist ablesbar (Fenster + Protokollkopf).
import { app } from 'electron'
import electronUpdater from 'electron-updater'
import { updateUrlPruefen } from './update-regeln'
export { STANDARD_UPDATE_URL, updateUrlPruefen } from './update-regeln'
const { autoUpdater } = electronUpdater
export interface UpdateStand {
/** Wann die letzte Prüfung GELANG — '' wenn noch nie. */
letzteErfolgreichePruefung: string
text: string
}
const stand: UpdateStand = { letzteErfolgreichePruefung: '', text: 'noch nicht geprüft' }
export function updateStand(): UpdateStand {
return { ...stand }
}
export function updateEinrichten(
eigeneUrl: string,
ripLaeuft: () => boolean,
melden: (text: string) => void,
): void {
if (!app.isPackaged) {
stand.text = 'Entwicklungslauf — Selbst-Update ist nur im installierten Rippy aktiv.'
return
}
const pruefung = updateUrlPruefen(eigeneUrl)
if (!pruefung.ok) {
stand.text = pruefung.grund
melden(pruefung.grund)
return
}
if (eigeneUrl.trim().length > 0) {
autoUpdater.setFeedURL({ provider: 'generic', url: eigeneUrl.trim() })
}
autoUpdater.autoDownload = false
// Installiert wird beim NÄCHSTEN Start — nie mitten in einem Rip.
autoUpdater.autoInstallOnAppQuit = true
autoUpdater.on('update-available', () => {
if (ripLaeuft()) {
// Regel 2: nicht einmal herunterladen, solange gerippt wird — der
// tägliche Takt versucht es wieder.
stand.text = 'Update verfügbar — wird geladen, sobald kein Rip läuft.'
return
}
void autoUpdater.downloadUpdate().catch((fehler: unknown) => {
stand.text = `Update-Download fehlgeschlagen: ${String(fehler)}`
})
})
autoUpdater.on('update-downloaded', (info) => {
stand.text = `Version ${info.version} liegt bereit — sie wird beim nächsten Start installiert.`
melden(stand.text)
})
autoUpdater.on('update-not-available', () => {
stand.letzteErfolgreichePruefung = new Date().toISOString()
stand.text = 'Rippy ist aktuell.'
})
autoUpdater.on('error', (fehler) => {
// Regel 3: still scheitern (WLAN weg, Server aus) — aber ablesbar.
stand.text = `Letzte Prüfung scheiterte: ${String(fehler).slice(0, 160)}`
})
const pruefen = (): void => {
if (ripLaeuft()) return
void autoUpdater.checkForUpdates().catch(() => {
// der error-Handler oben trägt den Grund ein
})
}
pruefen()
setInterval(pruefen, 24 * 60 * 60 * 1000).unref?.()
}