diff --git a/rippy-windows/electron.vite.config.ts b/rippy-windows/electron.vite.config.ts index 7b7a2cb..7873cab 100644 --- a/rippy-windows/electron.vite.config.ts +++ b/rippy-windows/electron.vite.config.ts @@ -24,7 +24,9 @@ function cspNurImBau(): Plugin { transformIndexHtml(html) { return html.replace( '
', - `\n `, + // img-src erlaubt TMDb-Poster (Kachel + Ändern-Dialog) — sonst + // bleibt alles bei 'self'. + `\n `, ) }, } diff --git a/rippy-windows/src/fenster/App.tsx b/rippy-windows/src/fenster/App.tsx index 149ffba..d5cd2b1 100644 --- a/rippy-windows/src/fenster/App.tsx +++ b/rippy-windows/src/fenster/App.tsx @@ -3,15 +3,33 @@ // Bibliothek (§ 6.6). Design-Sprache wie das heutige Rippy: dunkel, Kacheln. import { useEffect, useState } from 'react' import type { DiscInfoStand, GeraeteInfo, HauptStatus, RipStatus } from '../gemeinsam/nachrichten' +import { presetEmpfehlung } from '../gemeinsam/preset-empfehlung' import { aufVerbindung, auswerfen, einstellungSetzen, + metadatenSuchen, ripAbbrechen, ripStarten, verbindungStarten, + zuordnungSetzen, type Verbindung, } from './kernverbindung' +import type { MetaVorschlag } from '../gemeinsam/nachrichten' + +function posterUrlKlein(pfad: string): string { + if (pfad.length === 0) return '' + if (pfad.startsWith('http')) return pfad + return `https://image.tmdb.org/t/p/w154${pfad}` +} + +function restzeitText(prozent: number, startMs: number | undefined): string { + if (startMs === undefined || prozent <= 2 || prozent >= 100) return '' + const verstrichen = (Date.now() - startMs) / 1000 + const restS = Math.round((verstrichen * (100 - prozent)) / prozent) + if (restS < 90) return `· ~${restS} s` + return `· ~${Math.round(restS / 60)} min` +} function istHauptStatus(wert: unknown): wert is HauptStatus { return ( @@ -68,15 +86,101 @@ function Kachel({ titel, zustand, zeilen }: KachelProps) { ) } +// § 5 Schritt 4: „nein → fragen" — Suche + Auswahl der richtigen Metadaten. +function AendernDialog({ + id, + startText, + vorschlaege, + schliessen, +}: { + id: string + startText: string + vorschlaege: MetaVorschlag[] + schliessen: () => void +}) { + const [text, setText] = useState(startText) + useEffect(() => { + metadatenSuchen(id, startText) + // Nur beim Öffnen — weitere Suchen löst der Knopf aus. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + return ( +Keine Treffer — anderen Suchtext probieren.
+ ) : ( +{geraet.modell.length > 0 ? geraet.modell : 'Modell unbekannt'}
- {geraet.status === 'ready' && ( -- {TYP_NAMEN[geraet.typ]} - {geraet.groesseBytes > 0 ? ` · ${gb(geraet.groesseBytes)}` : ''} -
- )} - {geraet.status === 'ready' && info !== undefined && info.titel.length > 0 && ( -= 0.8 ? 'text-emerald-300' : 'text-amber-300'}> - {sicherheitsWort(info.confidence)}: {info.titel} - {info.jahr !== null ? ` (${info.jahr})` : ''} · {Math.round(info.confidence * 100)} % - {info.quelle.length > 0 ? ` · ${info.quelle}` : ''} -
- )} - {geraet.status === 'ready' && info !== undefined && info.schonGerippt !== null && ( -- ⚠ Diese Disc wurde schon einmal gerippt ({info.schonGerippt.slice(0, 10)}) — siehe Bibliothek. -
- )} - {geraet.status === 'empty' &&keine Disc eingelegt
} - {geraet.status === 'unknown' &&{geraet.grund}
} - {geraet.status !== 'unknown' && geraet.grund.length > 0 && ( -{geraet.grund}
+{geraet.modell.length > 0 ? geraet.modell : 'Modell unbekannt'}
+ {geraet.status === 'ready' && ( ++ {TYP_NAMEN[geraet.typ]} + {geraet.groesseBytes > 0 ? ` · ${gb(geraet.groesseBytes)}` : ''} +
+ )} + {geraet.status === 'ready' && info !== undefined && info.titel.length > 0 && ( += 0.8 ? 'text-emerald-300' : 'text-amber-300'}> + {sicherheitsWort(info.confidence)}: {info.titel} + {info.jahr !== null ? ` (${info.jahr})` : ''} · {Math.round(info.confidence * 100)} % + {info.quelle.length > 0 ? ` · ${info.quelle}` : ''} +
+ )} + {geraet.status === 'ready' && ( + + )} + {geraet.status === 'ready' && info !== undefined && info.schonGerippt !== null && ( ++ ⚠ Diese Disc wurde schon einmal gerippt ({info.schonGerippt.slice(0, 10)}) — siehe Bibliothek. +
+ )} + {geraet.status === 'empty' &&keine Disc eingelegt
} + {geraet.status === 'unknown' &&{geraet.grund}
} + {geraet.status !== 'unknown' && geraet.grund.length > 0 && ( +{geraet.grund}
+ )} +