feat(v5): Etappe W-2 — Rippen: Parser, makemkvcon-Lauf, Werkzeug-Katalog
Ampel / ampel (push) Failing after 1m22s
Ampel / ampel (push) Failing after 1m22s
rip/parser.ts: die reine Textverarbeitung mit allen bezahlten Fallen aus dem Docker-Zweig — quelle() (dev:G: statt dev:\.\G:, der 404-Verwandte), textVon() (UTF-8 streng, sonst cp1252 — nie wieder 'Öffnen'), parseMsg (Regex statt split — Meldungen mit Komma), PRGV (-1 vs. echtes 0 %), TINFO/SINFO (Sprache aus Attr 3/4, NICHT 28/29), laengsterTitel mit Play-All-Schutz, episodenTitel, KRITISCHE_CODES (sprachfeste NUMMERN). rip/makemkv.ts: Kommandobau + Lauf — ZeilenLeser (binaer, halbe Zeilen, je Zeile dekodiert), RipAuswertung (pur), rippen() mit AbortSignal, Lesefehler-Flag AUCH bei Rueckgabewert 0. werkzeuge/katalog.ts: die Suchreihenfolge samt %VAR%-Gross/Klein-Falle und Registry-Rueckfall. ablauf/rippen.ts: ein Rip je Laufwerk, Status-Push, 'erst nachsehen, dann rippen' (unbekannt heisst trotzdem rippen). Fenster: Rippen-Knopf, Fortschrittsbalken, Abbrechen; Auswurf waehrend des Rips abgelehnt. Gemessen am echten System (30.08.2026): Katalog findet makemkvcon64 (Program Files x86), HandBrakeCLI und flac (beide im rc11-Werkzeugordner LOCALAPPDATA\Rippy\tools). NEUER BEFUND: Nach dem abgebrochenen rc11-Rip vom Mittag sieht MakeMKV GAR KEIN Laufwerk mehr (MSG 5042, leere DRV-Liste, mit und ohne --noscan), waehrend die Storage-IOCTLs sauber antworten — MakeMKV spricht SCSI direkt. 5042 ist jetzt ein KRITISCHER_CODE mit Klartext-Abhilfe. Der volle Rip-Beweis (messung.rip.test.ts liegt bereit) braucht deshalb erst eine Hand am Geraet: Disc neu einlegen oder USB ab-/anstecken. 96 Tests gruen, Smoke gruen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a45069af5e
commit
844bca37ff
@@ -38,6 +38,20 @@ export type WacheEreignis =
|
||||
|
||||
export type AuswurfGrund = 'ok' | 'kein-zugriff' | 'abgelehnt' | 'bleibt-drin'
|
||||
|
||||
// ── Rippen (Etappe W-2) ─────────────────────────────────────────────────
|
||||
export type RipPhase = 'liest-info' | 'rippt' | 'fertig' | 'fehler' | 'abgebrochen'
|
||||
|
||||
export interface RipStatus {
|
||||
/** Laufwerks-Kennung, auf der der Rip läuft. */
|
||||
id: string
|
||||
phase: RipPhase
|
||||
/** 0–100; -1 heißt „noch keine Angabe" (ein echtes 0 % bleibt sichtbar). */
|
||||
prozent: number
|
||||
text: string
|
||||
dateien: string[]
|
||||
lesefehler: boolean
|
||||
}
|
||||
|
||||
/** Nachrichten, die der Kern verschickt. */
|
||||
export type KernNachricht =
|
||||
| { art: 'kern-bereit'; pid: number; nodeVersion: string; datenbank: DbStatus }
|
||||
@@ -45,9 +59,14 @@ export type KernNachricht =
|
||||
| { art: 'kern-fehler'; text: string }
|
||||
| { art: 'laufwerke'; liste: GeraeteInfo[]; ereignisse: WacheEreignis[] }
|
||||
| { art: 'auswurf-ergebnis'; id: string; grund: AuswurfGrund; fehler: string | null }
|
||||
| { art: 'rip-status'; status: RipStatus }
|
||||
|
||||
/** Nachrichten, die das Fenster über den MessagePort an den Kern schickt. */
|
||||
export type FensterNachricht = { art: 'ping'; zeit: number } | { art: 'auswerfen'; id: string }
|
||||
export type FensterNachricht =
|
||||
| { art: 'ping'; zeit: number }
|
||||
| { art: 'auswerfen'; id: string }
|
||||
| { art: 'rip-start'; id: string }
|
||||
| { art: 'rip-abbruch'; id: string }
|
||||
|
||||
/** Nachrichten, die das Haupt an den Kern schickt (Port-Übergabe). */
|
||||
export type HauptNachricht = { art: 'fenster-port' }
|
||||
@@ -85,11 +104,25 @@ export function istKernNachricht(wert: unknown): wert is KernNachricht {
|
||||
typeof wert.grund === 'string' &&
|
||||
(wert.fehler === null || typeof wert.fehler === 'string')
|
||||
)
|
||||
case 'rip-status':
|
||||
return istRipStatus(wert.status)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function istRipStatus(wert: unknown): wert is RipStatus {
|
||||
if (!istObjekt(wert)) return false
|
||||
return (
|
||||
typeof wert.id === 'string' &&
|
||||
typeof wert.phase === 'string' &&
|
||||
typeof wert.prozent === 'number' &&
|
||||
typeof wert.text === 'string' &&
|
||||
Array.isArray(wert.dateien) &&
|
||||
typeof wert.lesefehler === 'boolean'
|
||||
)
|
||||
}
|
||||
|
||||
export function istDbStatus(wert: unknown): wert is DbStatus {
|
||||
if (!istObjekt(wert)) return false
|
||||
if (wert.ok === true) return typeof wert.pfad === 'string'
|
||||
@@ -100,7 +133,9 @@ export function istDbStatus(wert: unknown): wert is DbStatus {
|
||||
export function istFensterNachricht(wert: unknown): wert is FensterNachricht {
|
||||
if (!istObjekt(wert)) return false
|
||||
if (wert.art === 'ping') return typeof wert.zeit === 'number'
|
||||
if (wert.art === 'auswerfen') return typeof wert.id === 'string' && wert.id.length > 0
|
||||
if (wert.art === 'auswerfen' || wert.art === 'rip-start' || wert.art === 'rip-abbruch') {
|
||||
return typeof wert.id === 'string' && wert.id.length > 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user