Files
rippy/rippy-windows/src/gemeinsam/vorgangsleiste.ts
T
HitonabiandClaude Fable 5.1 f5dab5d1c1 feat(v5): 5.6.0 — Vorgangs-Leiste, mehrere Filme je Disc, Filmnamen für Ordner und Dateien, Untertitel-Vorwahl je Extra, Restzeit, Hell-Modus
Die sechs Punkte des Commanders vom 02.09.2026 abends und seine Entscheide:

* Restzeit der Kompression aus HandBrakes eigener ETA-Klammer (Formatstring
  aus dem Binary 1.11.2 gelesen), KompressionStand.restS.
* Kachel zeigt nach dem Rip nur noch eine Zeile — Balken, Prozent, Ziel in
  der Kompressions-Karte und im Verlauf ("nur in der Kompressions-Karte").
* Kopfzeile bleibt beim Scrollen stehen (sticky), Sektionswahl darunter.
* Untertitel-Vorwahl je Extra ("NUR für Extras, IMMER OPTIONAL"): welche
  Untertitel-Spur beim Abspielen an ist — weiche Spur, nie eingebrannt;
  RipAuftragTitel/RohDatei.untertitelVorwahl, sprachwahl.
* Mehrere Filme je Disc: "anderer Film …" je Titel mit TMDb-Suche;
  filme.ts filmGruppen trennt am Rip-Ende in eigene Roh-Ordner, Vorgänge
  und Kompressions-Aufträge mit voller Zuordnung (erkennung.zuordnungAus).
* Roh-Ordner und Dateien tragen den Filmnamen (filme.ts rohOrdnerName,
  ablage/dateinamen.ts: Akira (1988).mkv, - Fassung n, - Extra nn).
* Hell-Modus: Einstellung design (dunkel/hell/system), data-design auf
  <html>, Token --color-tinte statt white/-Alpha-Klassen.
* Vorgangs-Leiste (Commander: "Phase 1–4 plus Komprimierung — zu einem
  machen"): gemeinsam/vorgangsleiste.ts + uebersicht/VorgangsLeiste.tsx,
  vier Stationen (Rettung als Zwischenstation), Segment-Balken in der
  aktiven Station; Kachel, Kompressions-Karte, Verlauf. PHASE-x/4-Texte weg.
* Automatik-Kasten leert sich, sobald ein Rip startet.

Beweise: 446 Tests (neu: filme, dateinamen, vorgangsleiste; erweitert:
auftrag, handbrake, automatik, ablegen), drei Typprüfungen, Klick-Beweis
33 Schritte inkl. Vorwahl, anderer Film, Vorgangs-Leiste, Restzeit,
Hell-Modus (Bilder beweise/klick/01…11).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 19:17:37 +02:00

144 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Die Vorgangs-Leiste (5.6.0, Commander: „Phase 14 plus Komprimierung —
// irgendwie zu einem machen, der Phasen-Balken gefällt mir") — EIN Weg für
// jede Disc, vier Stationen: Titel lesen → Rippen → Komprimieren → Ablegen,
// bei Bedarf das Rettungs-Abbild als Zwischenstation vor dem Rippen. Die
// Leiste zeigt immer den GANZEN Weg, aber nur an einer Stelle die Details:
// in der Laufwerks-Kachel, solange das Laufwerk arbeitet (Stationen 12),
// in der Kompressions-Karte danach (34), im Verlauf als Punkte.
//
// Hier liegt die REINE Logik (welche Station ist fertig, aktiv, offen,
// gescheitert) — testbar ohne React; gezeichnet wird in
// fenster/uebersicht/VorgangsLeiste.tsx.
import type { KompressionStand, RipStatus, VorgangEintrag } from './nachrichten'
export type Station = 'titel' | 'rettung' | 'rip' | 'kompression' | 'ablage'
export type LeisteZustand = 'laeuft' | 'wartet' | 'fertig' | 'fehler' | 'abgebrochen'
export type StationsZustand = 'fertig' | 'aktiv' | 'offen' | 'fehler'
export interface LeisteStand {
station: Station
zustand: LeisteZustand
/** 0100 in der aktiven Station, -1 = keine Angabe. */
prozent: number
/** Das Rettungs-Abbild als Zwischenstation zeigen. */
rettung: boolean
/** Kurztext in der aktiven Station („Platz 2", „läuft — Karte unten"). */
hinweis: string
}
export const STATIONS_NAMEN: Record<Station, string> = {
titel: 'Titel lesen',
rettung: 'Rettungs-Abbild',
rip: 'Rippen',
kompression: 'Komprimieren',
ablage: 'Ablegen',
}
export function stationen(rettung: boolean): Station[] {
return rettung ? ['titel', 'rettung', 'rip', 'kompression', 'ablage'] : ['titel', 'rip', 'kompression', 'ablage']
}
/** Zustand je Station: alles vor der aktiven ist fertig, die aktive läuft
* (oder ist gescheitert), alles danach ist offen. `fertig` = alle gold. */
export function stationsZustand(liste: readonly Station[], station: Station, zustand: LeisteZustand): StationsZustand[] {
const i = liste.indexOf(station)
return liste.map((_, k) => {
if (zustand === 'fertig') return 'fertig'
if (k < i) return 'fertig'
if (k === i) return zustand === 'fehler' || zustand === 'abgebrochen' ? 'fehler' : 'aktiv'
return 'offen'
})
}
function stand(station: Station, zustand: LeisteZustand, prozent = -1, rettung = false, hinweis = ''): LeisteStand {
return { station, zustand, prozent, rettung, hinweis }
}
/** Die Leiste in der Laufwerks-Kachel: aus dem Rip-Stand und — nach dem
* Rip — aus dem Vorgang (ohne Prozent: die Details stehen in der
* Kompressions-Karte). */
export function leisteAusRip(
rip: Pick<RipStatus, 'phase' | 'prozent' | 'rettung'>,
vorgang: Pick<VorgangEintrag, 'phase'> | undefined,
wartePlatz: number,
): LeisteStand {
const rettung = rip.phase === 'rettet' || rip.rettung !== undefined
switch (rip.phase) {
case 'liest-info':
return stand('titel', 'laeuft', -1, rettung)
case 'rettet':
return stand('rettung', 'laeuft', rip.prozent, true)
case 'rippt':
return stand('rip', 'laeuft', rip.prozent, rettung)
case 'komprimiert':
return stand('kompression', 'laeuft', rip.prozent, rettung)
case 'legt-ab':
return stand('ablage', 'laeuft', rip.prozent, rettung)
case 'fehler':
return stand('rip', 'fehler', -1, rettung)
case 'abgebrochen':
return stand('rip', 'abgebrochen', -1, rettung)
case 'fertig':
break
}
// Der Rip ist durch — wo steht der Vorgang?
if (vorgang === undefined) return stand('kompression', 'wartet', -1, rettung, 'eingereiht')
switch (vorgang.phase) {
case 'rippt':
return stand('rip', 'laeuft', -1, rettung)
case 'wartet':
return stand('kompression', 'wartet', -1, rettung, wartePlatz > 0 ? `Platz ${wartePlatz}` : 'wartet')
case 'komprimiert':
return stand('kompression', 'laeuft', -1, rettung, 'läuft — Karte unten')
case 'legt-ab':
return stand('ablage', 'laeuft', -1, rettung, 'läuft — Karte unten')
case 'fertig':
return stand('ablage', 'fertig', 100, rettung)
case 'fehler':
return stand('kompression', 'fehler', -1, rettung)
case 'abgebrochen':
return stand('kompression', 'abgebrochen', -1, rettung)
}
}
/** Die Leiste eines Vorgangs im Verlauf (kompakt). Bei Fehlern ohne
* Roh-Bytes scheiterte schon der Rip, sonst die Kompression. */
export function leisteAusVorgang(v: Pick<VorgangEintrag, 'phase' | 'rohBytes'>): LeisteStand {
switch (v.phase) {
case 'rippt':
return stand('rip', 'laeuft')
case 'wartet':
return stand('kompression', 'wartet', -1, false, 'wartet')
case 'komprimiert':
return stand('kompression', 'laeuft')
case 'legt-ab':
return stand('ablage', 'laeuft')
case 'fertig':
return stand('ablage', 'fertig', 100)
case 'fehler':
return stand(v.rohBytes > 0 ? 'kompression' : 'rip', 'fehler')
case 'abgebrochen':
return stand(v.rohBytes > 0 ? 'kompression' : 'rip', 'abgebrochen')
}
}
/** Die Leiste in der Kompressions-Karte: Stationen 12 sind fertig. */
export function leisteAusKompression(k: Pick<KompressionStand, 'phase' | 'prozent'>): LeisteStand {
switch (k.phase) {
case 'legt-ab':
return stand('ablage', 'laeuft', k.prozent)
case 'wartet':
return stand('kompression', 'wartet', -1, false, 'wartet')
case 'fertig':
return stand('ablage', 'fertig', 100)
case 'fehler':
return stand('kompression', 'fehler')
case 'abgebrochen':
return stand('kompression', 'abgebrochen')
case 'rippt':
return stand('rip', 'laeuft', k.prozent)
case 'komprimiert':
return stand('kompression', 'laeuft', k.prozent)
}
}