feat(v5): 5.5.0 — Kern und Oberfläche aufgeteilt, Übersicht und Einstellungen neu, Erst-Einrichtung mit Poster-Kulisse
Commander-Wünsche vom 02.09.2026 vor der Freigabe von 5.4.0 (die deshalb nie veröffentlicht wurde): Kern: kern/index.ts ist nur noch Bootstrap und Router; Dienste in kern/dienste/ (Einstellungen, Werkzeuge, Laufwerke, Erkennung, Vorgänge, Speicher, Benachrichtigung, Automatik), Kontext in kern/kontext.ts, Protokoll-Datei in gemeinsam/protokoll.ts, Platz-Rechnung in gemeinsam/platz.ts. Oberfläche: fenster/App.tsx ist nur noch der Rahmen; bausteine.tsx, dialoge/, uebersicht/ (LaufwerkKachel, KompressionsKarte, SpeicherKarte, VerlaufKarte), einstellungen/ (Karten je Funktion, SprachAuswahl), einrichtung/ (ErstEinrichtung, PosterHintergrund). Neu: Bibliothek weg, dafür Verlauf; Speicher-und-Bilanz-Karte (statfs); LED-Fußleiste; MakeMKV-Kopf in die Einstellungen; Sprach-Chips mit Dropdown statt Allgemeinem Preset; Karten Automatik/Benachrichtigung/Allgemein/Update; Durchsuchen bei Werkzeugen; Arbeitsordner lokal (Encode dort, dann in die Ablage); Platz-Prüfung vor dem Rip (Dialog und Kern); Automatik mit Countdown; Serien-Merker über Discs; Rettungs-Abbild mit Nullen nur nach gesehenen Lesefehlern (kern/rip/rettung.ts, Phase rettet, iso:-Quelle); Warteschlange pausieren; Discord/Telegram-Benachrichtigung; Protokoll-Datei je Tag; Fensterlage 80 % mittig, gemerkt; Erst-Einrichtung in acht Schritten vor dem Poster-Grid. Beweise: 413 Tests (neu: speicher, benachrichtigung, automatik, rettung, fensterlage, protokoll, kleinkram-550), drei Typprüfungen, Klick-Beweis mit 29 Schritten inklusive Erst-Einrichtung (zweiter Start mit RIPPY_START_BEREICH=einrichtung), Bilder beweise/klick/01…09. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
6678c81592
commit
3dc6798c79
@@ -45,6 +45,8 @@ export type AuswurfGrund = 'ok' | 'kein-zugriff' | 'abgelehnt' | 'bleibt-drin'
|
||||
// ── Rippen (Etappe W-2) ─────────────────────────────────────────────────
|
||||
export type RipPhase =
|
||||
| 'liest-info'
|
||||
/** 5.5.0: Das Rettungs-Abbild wird gelesen — Sektor für Sektor, Nullen für Unlesbares. */
|
||||
| 'rettet'
|
||||
| 'rippt'
|
||||
| 'komprimiert'
|
||||
| 'legt-ab'
|
||||
@@ -72,6 +74,12 @@ export interface RipStatus {
|
||||
/** Der Vorgang, zu dem dieser Rip gehört (5.4.0) — die Kompression läuft
|
||||
* danach unter dieser Kennung in der Warteschlange weiter. */
|
||||
vorgangId?: string
|
||||
/** 5.5.0: Rippy hat an dieser Disc Lesefehler GESEHEN (Defekt-Wächter,
|
||||
* Lesefehler-Meldung, Leseabbruch) — erst dann wird das Rettungs-Abbild
|
||||
* angeboten. Eine heile Disc braucht es nicht (Commander 01.09.2026). */
|
||||
rettungMoeglich?: boolean
|
||||
/** 5.5.0: Stand des Rettungs-Abbilds — unlesbare Sektoren und Stellen. */
|
||||
rettung?: { unlesbareSektoren: number; stellen: number }
|
||||
}
|
||||
|
||||
/** Was ein Titel IST — davon hängt ab, WOHIN er abgelegt wird:
|
||||
@@ -195,9 +203,13 @@ export interface DiscInfoStand {
|
||||
/** Was Rippy NACH dem Info-Lauf noch dazugelernt hat („Laufzeit
|
||||
* bestätigt: 124 min"), Klartext-Zeilen. */
|
||||
hinweise: string[]
|
||||
/** 5.5.0 Serien-Merker: Was Rippy von der VORIGEN Disc dieser Serie weiß —
|
||||
* Staffel und die Folge, mit der es weitergeht. null, wenn nichts. */
|
||||
serienMerker: { staffel: number; naechsteFolge: number; wann: string } | null
|
||||
}
|
||||
|
||||
/** Ein Eintrag der Bibliothek (§ 6.6). */
|
||||
/** Ein Eintrag der Bibliothek (§ 6.6) — seit 5.5.0 nur noch die
|
||||
* Wiedererkennung („schon gerippt am …"), keine eigene Ansicht mehr. */
|
||||
export interface BibliothekEintrag {
|
||||
fingerprint: string
|
||||
titel: string
|
||||
@@ -207,7 +219,7 @@ export interface BibliothekEintrag {
|
||||
ablageort: string
|
||||
datum: string
|
||||
dauerS: number
|
||||
/** TMDb-Posterpfad fürs Bibliotheks-Regal — '' wenn keiner bekannt. */
|
||||
/** TMDb-Posterpfad — '' wenn keiner bekannt. */
|
||||
posterPfad: string
|
||||
}
|
||||
|
||||
@@ -247,7 +259,7 @@ export interface BeschaffungStand {
|
||||
export type VorgangPhase = 'rippt' | 'wartet' | 'komprimiert' | 'legt-ab' | 'fertig' | 'fehler' | 'abgebrochen'
|
||||
|
||||
/** Ein Vorgang, wie das Fenster ihn zeigt (Einstellungen → Roh-Dateien,
|
||||
* Übersicht → Kompression). */
|
||||
* Übersicht → Verlauf). */
|
||||
export interface VorgangEintrag {
|
||||
id: string
|
||||
laufwerk: string
|
||||
@@ -289,6 +301,20 @@ export interface FremderOrdner {
|
||||
bytes: number
|
||||
}
|
||||
|
||||
/** 5.5.0: Was Rippy insgesamt geschafft hat (aus den Vorgängen). */
|
||||
export interface Statistik {
|
||||
/** Vorgänge insgesamt (Video-Discs). */
|
||||
discs: number
|
||||
/** Davon fertig abgelegt. */
|
||||
fertige: number
|
||||
/** Verlustfrei gesichert, Summe aller Rips (auch wenn Roh inzwischen weg ist). */
|
||||
rohBytes: number
|
||||
/** Fertig abgelegt, Summe. */
|
||||
fertigBytes: number
|
||||
/** Summe der Dauer je fertigem Vorgang (Rip-Beginn bis Ablage-Ende) in Sekunden. */
|
||||
dauerS: number
|
||||
}
|
||||
|
||||
export interface VorgaengeStand {
|
||||
vorgaenge: VorgangEintrag[]
|
||||
/** Summe aller Roh-Ordner, die noch da sind. */
|
||||
@@ -296,7 +322,8 @@ export interface VorgaengeStand {
|
||||
fremde: FremderOrdner[]
|
||||
/** Die Aufbewahrungs-Regel, die gerade gilt (Einstellung rohAufbewahrung). */
|
||||
regel: string
|
||||
kompression: { laeuft: KompressionStand | null; wartend: KompressionStand[] }
|
||||
kompression: { laeuft: KompressionStand | null; wartend: KompressionStand[]; pausiert: boolean }
|
||||
statistik: Statistik
|
||||
}
|
||||
|
||||
/** Was das Windows-Ereignisprotokoll über ein Laufwerk sagt (5.4.0). */
|
||||
@@ -313,6 +340,33 @@ export interface LaufwerkBericht {
|
||||
stunden: number
|
||||
}
|
||||
|
||||
/** 5.5.0: Freier Platz an EINEM Ort — gemessen mit fs.statfs (Node 24). */
|
||||
export interface SpeicherPlatz {
|
||||
pfad: string
|
||||
ok: boolean
|
||||
freiBytes: number
|
||||
gesamtBytes: number
|
||||
/** '' wenn ok — sonst, warum nicht messbar (Pfad fehlt, Netz weg). */
|
||||
fehler: string
|
||||
}
|
||||
|
||||
export interface SpeicherStand {
|
||||
/** Wo Roh-Dateien und Kompression liegen (Arbeitsordner oder Ablage). */
|
||||
arbeit: SpeicherPlatz
|
||||
/** Wo Fertiges landet (die Ablage — beim Commander der Server). */
|
||||
ablage: SpeicherPlatz
|
||||
/** true, wenn ein eigener Arbeitsordner gesetzt ist. */
|
||||
getrennt: boolean
|
||||
}
|
||||
|
||||
/** 5.5.0 Automatik: Countdown bis zum Rip ohne Klick (KONZEPT § 5 Zero-Click). */
|
||||
export interface AutomatikStand {
|
||||
id: string
|
||||
aktiv: boolean
|
||||
sekunden: number
|
||||
text: string
|
||||
}
|
||||
|
||||
/** Nachrichten, die der Kern verschickt. */
|
||||
export type KernNachricht =
|
||||
| { art: 'kern-bereit'; pid: number; nodeVersion: string; datenbank: DbStatus }
|
||||
@@ -329,7 +383,6 @@ export type KernNachricht =
|
||||
| { art: 'metadaten-vorschlaege'; id: string; vorschlaege: MetaVorschlag[] }
|
||||
| { art: 'einstellungen'; werte: Record<string, string> }
|
||||
| { art: 'werkzeuge'; auskunft: WerkzeugAuskunft }
|
||||
| { art: 'bibliothek'; eintraege: BibliothekEintrag[] }
|
||||
| { art: 'beschaffung-status'; stand: BeschaffungStand }
|
||||
/** Nur fürs Haupt: Der Kern hat einen geprüften Installer abgelegt —
|
||||
* starten kann ihn nur das Haupt (shell/UAC, § 9). */
|
||||
@@ -354,6 +407,12 @@ export type KernNachricht =
|
||||
/** Eine Kompression ist zu Ende — fürs Toast und die Ereignis-Zeile. */
|
||||
| { art: 'kompression-ergebnis'; vorgangId: string; titel: string; ok: boolean; text: string }
|
||||
| { art: 'laufwerk-gesundheit'; id: string; bericht: LaufwerkBericht }
|
||||
/** 5.5.0: freier Platz an Arbeitsordner und Ablage. */
|
||||
| { art: 'speicher'; stand: SpeicherStand }
|
||||
/** 5.5.0: Automatik-Countdown je Laufwerk. */
|
||||
| { art: 'automatik'; stand: AutomatikStand }
|
||||
/** 5.5.0: Poster beliebter Filme für den Hintergrund der Erst-Einrichtung. */
|
||||
| { art: 'poster-vorschau'; pfade: string[] }
|
||||
|
||||
/** Nachrichten, die das Fenster über den MessagePort an den Kern schickt. */
|
||||
export type FensterNachricht =
|
||||
@@ -374,7 +433,6 @@ export type FensterNachricht =
|
||||
| { art: 'zuordnung-setzen'; id: string; vorschlag: MetaVorschlag }
|
||||
| { art: 'einstellungen-laden' }
|
||||
| { art: 'werkzeuge-laden' }
|
||||
| { art: 'bibliothek-laden' }
|
||||
/** § 9: MakeMKV über die Quellenkette holen und installieren lassen. */
|
||||
| { art: 'makemkv-update' }
|
||||
/** Schlüsselkette sofort neu laufen lassen (z. B. nach einer Installation). */
|
||||
@@ -394,6 +452,20 @@ export type FensterNachricht =
|
||||
| { art: 'fremden-ordner-loeschen'; ordner: string }
|
||||
/** Das Windows-Ereignisprotokoll zu diesem Laufwerk lesen. */
|
||||
| { art: 'laufwerk-pruefen'; id: string }
|
||||
// ── 5.5.0 ──
|
||||
/** Die Kompressions-Warteschlange anhalten (an) oder weiterlaufen lassen. */
|
||||
| { art: 'kompression-pause'; an: boolean }
|
||||
/** Den Automatik-Countdown dieses Laufwerks stoppen bzw. sofort rippen. */
|
||||
| { art: 'automatik-stopp'; id: string }
|
||||
| { art: 'automatik-jetzt'; id: string }
|
||||
/** Testnachricht über die eingerichteten Kanäle (Discord, Telegram). */
|
||||
| { art: 'benachrichtigung-testen' }
|
||||
/** Poster beliebter Filme laden (Erst-Einrichtung). */
|
||||
| { art: 'poster-laden' }
|
||||
/** Rettungs-Abbild für eine Disc mit GESEHENEN Lesefehlern. */
|
||||
| { art: 'rettung-start'; id: string }
|
||||
/** Freien Platz neu messen. */
|
||||
| { art: 'speicher-laden' }
|
||||
|
||||
/** Nachrichten, die das Haupt an den Kern schickt. */
|
||||
export type HauptNachricht =
|
||||
@@ -413,6 +485,8 @@ export interface HauptStatus {
|
||||
/** Für die eigene Titelleiste (§ 4.2, seit 5.1.3): Ist das Fenster
|
||||
* gerade maximiert? Entscheidet nur, welches Symbol der Knopf zeigt. */
|
||||
fensterMaximiert: boolean
|
||||
/** 5.5.0: Wo die Protokoll-Dateien liegen — für „Protokoll öffnen". */
|
||||
protokollOrdner: string
|
||||
}
|
||||
|
||||
/** Der Stand des Selbst-Updates (§ 6.8) — EINE Definition, die sich Haupt
|
||||
@@ -489,8 +563,6 @@ export function istKernNachricht(wert: unknown): wert is KernNachricht {
|
||||
return istObjekt(wert.werte)
|
||||
case 'werkzeuge':
|
||||
return istObjekt(wert.auskunft) && Array.isArray((wert.auskunft as Record<string, unknown>).presets)
|
||||
case 'bibliothek':
|
||||
return Array.isArray(wert.eintraege)
|
||||
case 'schluessel-status':
|
||||
return istObjekt(wert.stand) && typeof (wert.stand as Record<string, unknown>).text === 'string'
|
||||
case 'beschaffung-status':
|
||||
@@ -509,7 +581,8 @@ export function istKernNachricht(wert: unknown): wert is KernNachricht {
|
||||
istObjekt(wert.stand) &&
|
||||
Array.isArray((wert.stand as Record<string, unknown>).vorgaenge) &&
|
||||
typeof (wert.stand as Record<string, unknown>).rohGesamtBytes === 'number' &&
|
||||
istObjekt((wert.stand as Record<string, unknown>).kompression)
|
||||
istObjekt((wert.stand as Record<string, unknown>).kompression) &&
|
||||
istObjekt((wert.stand as Record<string, unknown>).statistik)
|
||||
)
|
||||
case 'kompression-ergebnis':
|
||||
return (
|
||||
@@ -526,6 +599,23 @@ export function istKernNachricht(wert: unknown): wert is KernNachricht {
|
||||
typeof (wert.bericht as Record<string, unknown>).text === 'string' &&
|
||||
Array.isArray((wert.bericht as Record<string, unknown>).letzte)
|
||||
)
|
||||
case 'speicher':
|
||||
return (
|
||||
istObjekt(wert.stand) &&
|
||||
istObjekt((wert.stand as Record<string, unknown>).arbeit) &&
|
||||
istObjekt((wert.stand as Record<string, unknown>).ablage) &&
|
||||
typeof (wert.stand as Record<string, unknown>).getrennt === 'boolean'
|
||||
)
|
||||
case 'automatik':
|
||||
return (
|
||||
istObjekt(wert.stand) &&
|
||||
istKennung((wert.stand as Record<string, unknown>).id) &&
|
||||
typeof (wert.stand as Record<string, unknown>).aktiv === 'boolean' &&
|
||||
typeof (wert.stand as Record<string, unknown>).sekunden === 'number' &&
|
||||
typeof (wert.stand as Record<string, unknown>).text === 'string'
|
||||
)
|
||||
case 'poster-vorschau':
|
||||
return Array.isArray(wert.pfade) && wert.pfade.every(istText)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -597,10 +687,16 @@ export function istFensterNachricht(wert: unknown): wert is FensterNachricht {
|
||||
wert.art === 'titel-lesen' ||
|
||||
wert.art === 'rip-abbruch' ||
|
||||
wert.art === 'rip-ueberspringen' ||
|
||||
wert.art === 'laufwerk-pruefen'
|
||||
wert.art === 'laufwerk-pruefen' ||
|
||||
wert.art === 'automatik-stopp' ||
|
||||
wert.art === 'automatik-jetzt' ||
|
||||
wert.art === 'rettung-start'
|
||||
) {
|
||||
return istKennung(wert.id)
|
||||
}
|
||||
if (wert.art === 'kompression-pause') {
|
||||
return typeof wert.an === 'boolean'
|
||||
}
|
||||
if (wert.art === 'einstellung-setzen') {
|
||||
return istKennung(wert.schluessel) && typeof wert.wert === 'string'
|
||||
}
|
||||
@@ -622,11 +718,13 @@ export function istFensterNachricht(wert: unknown): wert is FensterNachricht {
|
||||
return (
|
||||
wert.art === 'einstellungen-laden' ||
|
||||
wert.art === 'werkzeuge-laden' ||
|
||||
wert.art === 'bibliothek-laden' ||
|
||||
wert.art === 'makemkv-update' ||
|
||||
wert.art === 'schluessel-pruefen' ||
|
||||
wert.art === 'vorgaenge-laden' ||
|
||||
wert.art === 'roh-aufraeumen'
|
||||
wert.art === 'roh-aufraeumen' ||
|
||||
wert.art === 'benachrichtigung-testen' ||
|
||||
wert.art === 'poster-laden' ||
|
||||
wert.art === 'speicher-laden'
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user