style: echte Umlaute im ganzen Projekt + Installer im Rippy-Look
Ampel / ampel (push) Successful in 27s
Ampel / ampel (push) Successful in 27s
Commander-Rueckmeldung: Umlaute fehlen. Ausloeser war sichtbar der Installer -
"Diese Maschine uebernimmt die Video-Kompression fuer Rippy" stand woertlich im
Screenshot.
## Die .ps1-Falle war loesbar, nicht unumgehbar
Bisher galt: ausgelieferte .ps1 MUESSEN ASCII sein, weil PowerShell 5.1 sie
ohne BOM als ANSI liest. Das ist nur die halbe Wahrheit - gemessen mit echtem
powershell.exe 5.1:
ohne BOM: $s = "Größe: äöü" + Unerwartetes Token -> Skript kaputt
mit BOM: Groesse: aeoeue + laeuft, Length 16 korrekt
Alle drei Skripte sind jetzt UTF-8 MIT BOM und tragen echte Umlaute; unter 5.1
gegengeprueft (BOM vorhanden, Parser fehlerfrei, Text korrekt gelesen). Der
Kopfkommentar sagt das jetzt richtig statt "ASCII-only".
## Umstellung: Text ja, Bezeichner nein
Umlaute gehoeren in Kommentare und Anzeigetexte, nicht in Funktionsnamen oder
Datenschluessel. Deshalb je Sprache das passende Werkzeug:
- Python: ueber den TOKENIZER - angefasst wurden ausschliesslich COMMENT- und
STRING-Tokens. 156 Stellen. Code ist damit garantiert unberuehrt.
- TypeScript: nur // und /* */ Kommentare sowie JSX-Text (kann per Definition
kein Bezeichner sein). 24 Stellen. `const waehlen`, `let laeuft`, `plaetze`,
`GeraetInfo` sind nachweislich unversehrt.
- install.sh: Anzeigetext, aber die Shell-Funktionen (gruen/rot/gelb/titel) und
der Schalter --nur-pruefen bleiben ASCII - das sind Schnittstellen.
- Markdown: 0 Aenderungen, die Doku hatte schon Umlaute.
ZWEI FEHLER MEINES KONVERTERS, beide von Werkzeugen gefangen:
1. In f-Strings steht in {...} CODE, kein Text. Aus f"{groesse}" wurde
f"{größe}", waehrend die Variable groesse hiess - Ruff meldete F821
"Undefined name". Der Konverter lagert Einsetzungen jetzt aus.
2. Ein Dict-Schluessel wurde umbenannt: die Wortliste enthaelt das PRAEFIX
"uebersprung", der Tabu-Schutz prueft aber ganze Woerter. bericht[...] ist
wieder ASCII - Umlaute in Datenschluesseln brechen JSON-Runden und DB-Felder.
## Installer im Rippy-Look
Statt hellgrau jetzt dieselben Toene wie das Web-UI (aus lib/design.ts
uebernommen): slate-900 Flaeche, dunkle Eingabefelder, Amber-Hauptknopf wie
"Los geht's" im Wizard. Oben ein Kopfbereich mit dem Farbverlauf
amber -> indigo -> purple und dem Disc-Symbol - in WinForms per Paint-Ereignis
gezeichnet, weil es dort keine Verlaeufe von der Stange gibt.
Geprueft, nicht gehofft: Das Fenster wurde headless in ein PNG gerendert
(DrawToBitmap) und angesehen - Verlauf, Symbol, Umlaute und Farben sitzen.
RippyWorkerSetup.exe neu gebaut (57344 -> 60416 Bytes); Umlaute und das
requireAdministrator-Manifest sind in der .exe verifiziert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,12 +37,12 @@ const ENCODER_LABELS: Record<string, string> = {
|
||||
// braucht roh rund 40 GB, eine 4K-UHD bis 100 GB.
|
||||
const PLATZ_WARNUNG_GB = 60
|
||||
|
||||
/** Was beim Abschliessen gespeichert wird — abhaengig davon, was die Maschine kann. */
|
||||
/** Was beim Abschliessen gespeichert wird — abhängig davon, was die Maschine kann. */
|
||||
function presetsFuer(schwach: boolean) {
|
||||
if (schwach) {
|
||||
// Gemessen auf einer CPU ohne AVX2: 4K-HEVC = 28-55 h pro Film. Also 4K
|
||||
// verlustfrei behalten und fuer den Rest H.264 nehmen (deutlich schneller
|
||||
// als H.265, dafuer etwas groesser).
|
||||
// verlustfrei behalten und für den Rest H.264 nehmen (deutlich schneller
|
||||
// als H.265, dafür etwas größer).
|
||||
return {
|
||||
transcodePreset: 'HQ 1080p30 Surround',
|
||||
transcodePresetBluray: 'HQ 1080p30 Surround',
|
||||
@@ -72,7 +72,7 @@ export default function FirstRunWizard({ onDone }: { onDone: () => void }) {
|
||||
const [keyWarnung, setKeyWarnung] = useState<string | null>(null)
|
||||
|
||||
// Wiederholt laden, bis Worker UND Laufwerk da sind: beim allerersten Start
|
||||
// laeuft der Worker-Container oft noch hoch. Ohne das stand hier dauerhaft
|
||||
// läuft der Worker-Container oft noch hoch. Ohne das stand hier dauerhaft
|
||||
// „Noch kein Worker gemeldet" und der Nutzer wusste nicht, ob er warten soll.
|
||||
useEffect(() => {
|
||||
let laeuft = true
|
||||
@@ -112,8 +112,8 @@ export default function FirstRunWizard({ onDone }: { onDone: () => void }) {
|
||||
transcodeEnabled,
|
||||
...presets,
|
||||
})
|
||||
// Erst SPEICHERN, dann pruefen: /metadata/status liest die Keys aus der
|
||||
// Datenbank, nicht aus dem Formular. Ein falsch kopierter Key faellt so
|
||||
// Erst SPEICHERN, dann prüfen: /metadata/status liest die Keys aus der
|
||||
// Datenbank, nicht aus dem Formular. Ein falsch kopierter Key fällt so
|
||||
// sofort auf, statt erst beim ersten Rip als „Unknown Disc".
|
||||
if (tmdbKey.trim() || omdbKey.trim()) {
|
||||
try {
|
||||
@@ -131,7 +131,7 @@ export default function FirstRunWizard({ onDone }: { onDone: () => void }) {
|
||||
return // nicht wegklicken, damit die Warnung gelesen wird
|
||||
}
|
||||
} catch {
|
||||
// Pruefung selbst kaputt → kein Grund, die Einrichtung zu blockieren
|
||||
// Prüfung selbst kaputt → kein Grund, die Einrichtung zu blockieren
|
||||
}
|
||||
}
|
||||
await api.post('/setup/complete')
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function WorkerVerwaltung() {
|
||||
: [
|
||||
// Standard-Ziel ist "C:\Program Files\Rippy Worker" - dorthin darf nur
|
||||
// ein Administrator schreiben, deshalb der Hinweis direkt im Befehl.
|
||||
// Die .exe fragt selbst per UAC; hier muss die Konsole erhoeht sein.
|
||||
// Die .exe fragt selbst per UAC; hier muss die Konsole erhöht sein.
|
||||
`# PowerShell als Administrator starten (Standard-Ziel: Programme)`,
|
||||
`iwr http://${hostFuerBefehl}/api/worker-setup/windows -OutFile install-rippy-worker.ps1`,
|
||||
`powershell -ExecutionPolicy Bypass -File .\\install-rippy-worker.ps1 \``,
|
||||
|
||||
@@ -72,8 +72,8 @@ interface WorkerInfo {
|
||||
encoders: string[]
|
||||
// keydb: "ja" | "nein" | "unbekannt" — sagt, ob DIESER Worker eine KEYDB.cfg
|
||||
// in seinem MakeMKV-Datenverzeichnis sieht. Nur der Worker, der wirklich
|
||||
// rippt, zaehlt, deshalb steht die Angabe pro Worker und nicht global.
|
||||
// cpu_kerne/cpu_simd: Rechenleistung fuers Software-Encodieren. Ohne diese
|
||||
// rippt, zählt, deshalb steht die Angabe pro Worker und nicht global.
|
||||
// cpu_kerne/cpu_simd: Rechenleistung fürs Software-Encodieren. Ohne diese
|
||||
// Angaben war am 25.07.2026 nicht zu sehen, dass ein 4K-Encode auf der
|
||||
// Rippy-VM Tage statt Stunden braucht (kein AVX2, 4 Kerne).
|
||||
// handbrake_encoder: die ungefilterte Encoder-Auskunft von HandBrake selbst.
|
||||
@@ -101,7 +101,7 @@ interface StorageZiel {
|
||||
free_gb: number | null
|
||||
}
|
||||
|
||||
// Antwort von GET/POST /system/keystore — MakeMKVs eigener Schluesselvorrat.
|
||||
// Antwort von GET/POST /system/keystore — MakeMKVs eigener Schlüsselvorrat.
|
||||
interface KeystoreStatus {
|
||||
vorhanden: boolean
|
||||
pfad: string
|
||||
@@ -125,7 +125,7 @@ interface SystemInfo {
|
||||
webhook_gesetzt: boolean
|
||||
}
|
||||
|
||||
// Byte-Zahl menschenlesbar — eine echte KEYDB.cfg ist mehrere MB gross.
|
||||
// Byte-Zahl menschenlesbar — eine echte KEYDB.cfg ist mehrere MB groß.
|
||||
function bytesLesbar(bytes: number): string {
|
||||
if (!bytes) return '0 B'
|
||||
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
@@ -134,7 +134,7 @@ function bytesLesbar(bytes: number): string {
|
||||
}
|
||||
|
||||
// Die API liefert ISO-8601 in UTC (oder einen leeren String). Ohne Zonen-Kennung
|
||||
// wuerde der Browser den Zeitstempel als Ortszeit lesen und die Uhrzeit um den
|
||||
// würde der Browser den Zeitstempel als Ortszeit lesen und die Uhrzeit um den
|
||||
// Zonen-Versatz verschieben — deshalb notfalls ein Z anhaengen.
|
||||
function zeitLesbar(iso: string): string {
|
||||
if (!iso) return 'unbekannt'
|
||||
@@ -158,7 +158,7 @@ export default function SettingsPage() {
|
||||
const [updatesBusy, setUpdatesBusy] = useState(false)
|
||||
// KEYDB.cfg und AACS-Dumps sind DATEIEN im MakeMKV-Datenverzeichnis, keine
|
||||
// Einstellungen — deshalb bewusst NICHT in SettingsState: der globale
|
||||
// Speichern-Knopf postet dieses Objekt komplett und wuerde sie mitschleifen.
|
||||
// Speichern-Knopf postet dieses Objekt komplett und würde sie mitschleifen.
|
||||
const [keydb, setKeydb] = useState<KeydbStatus | null>(null)
|
||||
const [keydbBusy, setKeydbBusy] = useState(false)
|
||||
const [dumps, setDumps] = useState<AacsDump[]>([])
|
||||
@@ -200,7 +200,7 @@ export default function SettingsPage() {
|
||||
// letzten Herzschlag des Workers (minuetlich) — ohne dieses Nachladen
|
||||
// widerspraeche die Kachel nach einem Upload sichtbar der Erfolgsmeldung.
|
||||
// Ganz sofort ist sie trotzdem nicht: der Worker meldet erst beim
|
||||
// naechsten Herzschlag neu. Genau so steht es auch im Erklaertext.
|
||||
// nächsten Herzschlag neu. Genau so steht es auch im Erklaertext.
|
||||
api.get('/capabilities').then(r => setWorkers(r.data.workers || [])).catch(() => setWorkers([]))
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export default function SettingsPage() {
|
||||
setKeydbBusy(true)
|
||||
try {
|
||||
// Bewusst als JSON-Text und nicht als Multipart-Upload: der API fehlt
|
||||
// python-multipart, ein File()-Endpunkt wuerde sie beim Import killen.
|
||||
// python-multipart, ein File()-Endpunkt würde sie beim Import killen.
|
||||
const inhalt = await datei.text()
|
||||
await api.post('/system/keydb', { inhalt })
|
||||
keydbLaden()
|
||||
@@ -436,9 +436,9 @@ export default function SettingsPage() {
|
||||
|
||||
{/* Der Schalter „Alle Tracks rippen" ist am 25.07.2026 entfallen.
|
||||
Er war ein Placebo: abcde bekommt keine Track-Auswahl (siehe
|
||||
build_abcde_cmd) und es gibt auch keine Oberflaeche, um eine
|
||||
Teilmenge zu waehlen — eine Audio-CD wurde also immer
|
||||
vollstaendig gerippt, egal wie der Schalter stand. Statt einer
|
||||
build_abcde_cmd) und es gibt auch keine Oberfläche, um eine
|
||||
Teilmenge zu wählen — eine Audio-CD wurde also immer
|
||||
vollständig gerippt, egal wie der Schalter stand. Statt einer
|
||||
Wahl, die nichts bewirkt, steht hier jetzt die Wahrheit. */}
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 px-1">
|
||||
💿 Eine Audio-CD wird immer vollständig gerippt — alle Tracks als
|
||||
@@ -892,9 +892,9 @@ export default function SettingsPage() {
|
||||
</span>
|
||||
)}
|
||||
{/*
|
||||
Nur das Verzeichnis des rippenden Workers zaehlt — deshalb je Worker.
|
||||
Die Zahl der Disc-Schluessel ist die entscheidende Angabe fuer 4K-UHD:
|
||||
0 heisst, dass JEDE unbekannte UHD-Disc scheitert.
|
||||
Nur das Verzeichnis des rippenden Workers zählt — deshalb je Worker.
|
||||
Die Zahl der Disc-Schluessel ist die entscheidende Angabe für 4K-UHD:
|
||||
0 heißt, dass JEDE unbekannte UHD-Disc scheitert.
|
||||
*/}
|
||||
{w.info?.schluessel && w.info.schluessel !== '0' && w.info.schluessel !== 'unbekannt' && (
|
||||
<span className="text-xs px-2.5 py-0.5 rounded-md font-medium bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30">
|
||||
@@ -919,7 +919,7 @@ export default function SettingsPage() {
|
||||
Disc-Schluessel-Datenbank mit. Nachgemessen: falsch — MakeMKV liefert
|
||||
gar keine Schluessel mit, es holt sie zur Laufzeit. Und die
|
||||
Linux-Version holt sie nie (kein einziger Verbindungsversuch, auf
|
||||
beiden Maschinen verglichen). Deshalb der Schluesselspeicher unten.
|
||||
beiden Maschinen verglichen). Deshalb der Schlüsselspeicher unten.
|
||||
*/}
|
||||
<p className="text-xs mt-3 pt-3 border-t border-slate-200/60 dark:border-slate-800 text-slate-500 dark:text-slate-400">
|
||||
<strong className="text-slate-700 dark:text-slate-300">MakeMKV</strong> lässt sich aktuell halten
|
||||
@@ -943,7 +943,7 @@ export default function SettingsPage() {
|
||||
/>
|
||||
|
||||
{/*
|
||||
Schluesselspeicher — der Hauptweg fuer 4K-UHD (Befund 25.07.2026,
|
||||
Schlüsselspeicher — der Hauptweg für 4K-UHD (Befund 25.07.2026,
|
||||
auf beiden Maschinen gemessen): makemkvcon holt Disc-Schluessel
|
||||
unter Linux NIE selbst, die Windows-Version tut es (Meldung 3338,
|
||||
Verbindung nach 185.84.108.20:443). Deshalb wird der Vorrat hier
|
||||
@@ -1019,8 +1019,8 @@ export default function SettingsPage() {
|
||||
|
||||
{/*
|
||||
KEYDB.cfg — der NOTNAGEL, nicht der Hauptweg. Sie hilft bei Pressungen,
|
||||
die auch MakeMKV selbst nicht kennt. Der Regelfall laeuft ueber den
|
||||
Schluesselspeicher im Block darueber. Dateiname GROSS geschrieben, unter
|
||||
die auch MakeMKV selbst nicht kennt. Der Regelfall läuft über den
|
||||
Schlüsselspeicher im Block darüber. Dateiname GROSS geschrieben, unter
|
||||
Linux case-sensitiv. Rippy stellt nur den Platz bereit.
|
||||
*/}
|
||||
<div className="p-4 rounded-xl border border-slate-200/80 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-950/80 space-y-3">
|
||||
@@ -1107,7 +1107,7 @@ export default function SettingsPage() {
|
||||
|
||||
{/*
|
||||
AACS-Dumps: MakeMKV legt sie bei einer unbekannten UHD-Disc ab (Meldung 3332).
|
||||
Seit das Datenverzeichnis persistent gemountet ist, ueberleben sie den
|
||||
Seit das Datenverzeichnis persistent gemountet ist, überleben sie den
|
||||
Container-Neustart — vorher waren sie nach jedem Rip weg.
|
||||
*/}
|
||||
<div className="p-4 rounded-xl border border-slate-200/80 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-950/80 space-y-3">
|
||||
|
||||
Reference in New Issue
Block a user