35cfcbcb07
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>
119 lines
4.9 KiB
Python
119 lines
4.9 KiB
Python
"""Tests für die puren Helfer aus makemkv_daten.
|
|
|
|
Bewusst OHNE Dateisystem, DB und fcntl — deshalb laufen sie auch auf Windows
|
|
und nicht nur in der Ampel. Geprueft wird genau das, was ohne Container und
|
|
ohne echte Disc entscheidbar ist: das Zeilenformat der KEYDB.cfg, die
|
|
Plausibilitaetspruefung beim Hochladen, die Namenshaerte der AACS-Dumps und
|
|
das Zusammenfuehren der settings.conf.
|
|
"""
|
|
from makemkv_daten import (
|
|
ist_aacs_dump,
|
|
keydb_pruefen,
|
|
settings_conf_zusammenfuehren,
|
|
zaehle_disc_eintraege,
|
|
)
|
|
|
|
# Echte Beispielzeilen im libaacs-Format: 40 Hex-Zeichen Disc-Kennung, dann
|
|
# "= Titel". Zweite Zeile mit 0x-Praefix, weil die oeffentlichen Dateien beide
|
|
# Schreibweisen mischen (Fundstelle steht im Modul-Docstring von makemkv_daten).
|
|
_GUELTIG = """; KEYDB.cfg — Beispiel
|
|
|
|
0123456789ABCDEF0123456789ABCDEF01234567 = Akira
|
|
0xFEDCBA9876543210FEDCBA9876543210FEDCBA98 = Blade Runner | V | 00112233445566778899AABBCCDDEEFF
|
|
"""
|
|
|
|
|
|
def test_zaehle_disc_eintraege_zaehlt_nur_echte_disc_zeilen():
|
|
# Kommentar- und Leerzeilen dürfen NICHT mitgezaehlt werden, sonst meldet
|
|
# das UI "da liegt was drin", obwohl die Datei keinen Schluessel enthält.
|
|
assert zaehle_disc_eintraege(_GUELTIG) == 2
|
|
|
|
|
|
def test_zaehle_disc_eintraege_ohne_disc_zeile_ist_null():
|
|
nur_kommentare = "; nur ein Kommentar\n\n;noch einer\n"
|
|
assert zaehle_disc_eintraege(nur_kommentare) == 0
|
|
assert zaehle_disc_eintraege("") == 0
|
|
|
|
|
|
def test_zaehle_disc_eintraege_akzeptiert_0x_praefix_einzeln():
|
|
assert zaehle_disc_eintraege("0x0123456789abcdef0123456789abcdef01234567 = Tenet") == 1
|
|
|
|
|
|
def test_zaehle_disc_eintraege_lehnt_zu_kurze_kennung_ab():
|
|
# 39 statt 40 Hex-Zeichen: das ist keine Disc-Kennung, sondern Tippfehler
|
|
# oder eine abgeschnittene Datei — darf nicht als Eintrag durchgehen.
|
|
assert zaehle_disc_eintraege("0123456789ABCDEF0123456789ABCDEF0123456 = Kurz") == 0
|
|
|
|
|
|
def test_keydb_pruefen_meldet_leere_datei():
|
|
assert keydb_pruefen("") != ""
|
|
assert keydb_pruefen(" \n\n ") != ""
|
|
|
|
|
|
def test_keydb_pruefen_erkennt_html():
|
|
# Häufigster Bedienfehler: statt der Datei landet die HTML-Fehlerseite
|
|
# eines Downloads im Feld. MakeMKV würde dann still weiter meckern.
|
|
fehler = keydb_pruefen("<!DOCTYPE html>\n<html><body>404 Not Found</body></html>\n")
|
|
assert "HTML" in fehler
|
|
|
|
|
|
def test_keydb_pruefen_meldet_datei_ohne_disc_zeile():
|
|
# Text ist da, aber keine einzige Disc-Kennung — z. B. eine Liesmich-Datei.
|
|
assert keydb_pruefen("Das hier ist irgendein Text ohne Schluessel.\n") != ""
|
|
|
|
|
|
def test_keydb_pruefen_laesst_gueltige_datei_durch():
|
|
# "" heißt laut Vertrag: alles in Ordnung, darf geschrieben werden.
|
|
assert keydb_pruefen(_GUELTIG) == ""
|
|
|
|
|
|
def test_ist_aacs_dump_erkennt_echten_namen():
|
|
# So heißt der Dump, den MakeMKV am 25.07.2026 für Akira UHD abgelegt hat
|
|
# (Meldung 3332) — dieser Name MUSS zum Download durchkommen.
|
|
assert ist_aacs_dump("MKB20_v76_UHD_AKIRA_C02B.tgz") is True
|
|
|
|
|
|
def test_ist_aacs_dump_blockt_pfad_tricks():
|
|
# Der Download-Endpunkt hängt den Namen an das Datenverzeichnis — ein
|
|
# durchgelassenes ".." oder ein Pfadtrenner wäre ein Ausbruch.
|
|
assert ist_aacs_dump("../x.tgz") is False
|
|
assert ist_aacs_dump("../../etc/passwd.tgz") is False
|
|
assert ist_aacs_dump("unter/ordner.tgz") is False
|
|
assert ist_aacs_dump("unter\\ordner.tgz") is False
|
|
assert ist_aacs_dump(".versteckt.tgz") is False
|
|
|
|
|
|
def test_ist_aacs_dump_lehnt_andere_endungen_ab():
|
|
# Nur die Dumps sollen abholbar sein — nicht settings.conf, nicht
|
|
# _private_data.tar und schon gar nicht die KEYDB.cfg selbst.
|
|
assert ist_aacs_dump("KEYDB.cfg") is False
|
|
assert ist_aacs_dump("settings.conf") is False
|
|
assert ist_aacs_dump("_private_data.tar") is False
|
|
assert ist_aacs_dump("") is False
|
|
|
|
|
|
def test_settings_conf_ersetzt_alten_key_und_behaelt_den_rest():
|
|
# Regression: bis 25.07.2026 wurde die Datei komplett überschrieben. Mit
|
|
# dem jetzt persistenten Datenverzeichnis wäre app_UpdateEnable vor jedem
|
|
# Rip weg gewesen.
|
|
alt = 'app_UpdateEnable = "1"\napp_Key = "T-alt"\napp_DestinationDir = "/tmp"\n'
|
|
neu = settings_conf_zusammenfuehren(alt, "T-neu")
|
|
assert 'app_Key = "T-neu"' in neu
|
|
assert "T-alt" not in neu
|
|
assert 'app_UpdateEnable = "1"' in neu
|
|
assert 'app_DestinationDir = "/tmp"' in neu
|
|
|
|
|
|
def test_settings_conf_leerer_key_entfernt_die_zeile():
|
|
# Ein bewusst geleerter Key darf nicht heimlich weiterwirken.
|
|
neu = settings_conf_zusammenfuehren('app_Key = "T-alt"\napp_UpdateEnable = "1"\n', "")
|
|
assert "app_Key" not in neu
|
|
assert 'app_UpdateEnable = "1"' in neu
|
|
|
|
|
|
def test_settings_conf_aus_dem_nichts_endet_mit_zeilenumbruch():
|
|
# Erster Start: es gibt noch keine settings.conf. MakeMKV erwartet eine
|
|
# Datei mit abschliessendem Zeilenumbruch.
|
|
assert settings_conf_zusammenfuehren("", "T-neu") == 'app_Key = "T-neu"\n'
|
|
assert settings_conf_zusammenfuehren("", "") == ""
|