feat(v5): Kern 5.4.0 — Vorgaenge, Kompressions-Warteschlange, Roh-Aufraeumen, Sprachen je Titel, Erkennung v2
WAS: Der Rip endet, sobald die Roh-Dateien liegen; die Kompression laeuft danach in einer Warteschlange (eine zur Zeit), das Laufwerk ist frei fuer die naechste Disc. Jeder Rip ist jetzt ein Datensatz (Tabelle vorgaenge, Schema 4): Roh-Ordner, Zielordner, Phase, Auftrag als JSON. Darauf bauen: Roh-Aufraeumen nach Regel (Vorgabe 7 Tage, nur bei gelungener Kompression und nur wenn jede fertige Datei da und nicht leer ist), Wiederholen ab Kompression, Aufraeumen halber Dateien nach Abbruch/Fehler, Wiederaufnahme nach Neustart. Unkomprimierte Rips (4K, kein HandBrake) werden in den Zielordner VERSCHOBEN statt unter roh\ liegen zu bleiben. Sprachen je Titel reisen vom Info-Lauf (SINFO) bis in HandBrake; fremder Ton schaltet den deutschen Untertitel vor (--subtitle-default=1). Vor der Kompression prueft ein HandBrake-Scan die Roh-Datei. MakeMKVs Auswahlregel wird gesetzt, wenn keine steht, damit alle Sprachen in die Roh-Datei kommen. Staffel und erste Folge von Hand schlagen die Laufzeit-Raterei. Durchgehender Fortschritt, nach Groesse gewichtet. Erkennung v2: leere TMDb-Eintraege (Stubs) zaehlen nicht, Laufzeit wird nach dem Info-Lauf gegen TMDb gehalten, Titel-Struktur als Fingerabdruck, bdmt_deu als zweite Titel-Variante. TMDb liefert Logo, Tagline, Bewertung, FSK und Besetzung in derselben Anfrage. Laufwerks-Gesundheit aus dem Windows-Ereignisprotokoll (wevtutil): Disc oder Hardware. WARUM: Uebergabe-Punkte 1-5, 8-12 des SAVEPOINT vom 01.09.2026 — vom Commander gutgeheissen (7 Tage / Untertitel vorgewaehlt / entkoppelte Kompression waren seine Wahl). GEMESSEN (Regel D): HandBrake 1.11 Sprach-Schalter an einer ffmpeg- Testdatei (jpn/deu/deu/eng + deu/eng), HandBrake --scan --json Format, TMDb movie/149 + tv/46296 mit append_to_response, wevtutil /f:xml an diesem PC (338x cdrom 7, 8x cdrom 11 in 30 Tagen), makemkvcon --minlength, MakeMKV-Auswahlregel laut forum.makemkv.com t=4386. 348 Tests gruen (vorher 261), Typpruefung und Bau gruen. Oberflaeche folgt im naechsten Schritt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d70a81d194
commit
3f7f962dff
@@ -0,0 +1,62 @@
|
||||
// Tests des HandBrake-Scans (kern/komprimieren/scan.ts, 5.4.0) — am
|
||||
// gemessenen Format: „JSON Title Set:" + Objekt + weiterer Text.
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildScanArgs, fehlendeSprachen, spurenAusScan } from '../src/kern/komprimieren/scan'
|
||||
import { regelAusQuery, RIPPY_REGEL } from '../src/kern/werkzeuge/spurauswahl'
|
||||
|
||||
const AUSGABE = `[21:27:54] hb_init: starting libhb thread
|
||||
Scanning title 1 of 1, preview 1, 25.00 %
|
||||
JSON Title Set: {
|
||||
"MainFeature": 0,
|
||||
"TitleList": [
|
||||
{
|
||||
"AudioList": [
|
||||
{ "Description": "\u65e5\u672c\u8a9e (AAC LC, 2.0 ch)", "Language": "\u65e5\u672c\u8a9e", "LanguageCode": "jpn", "TrackNumber": 1 },
|
||||
{ "Description": "Deutsch (AAC LC, 2.0 ch)", "Language": "Deutsch", "LanguageCode": "deu", "TrackNumber": 2 },
|
||||
{ "Description": "English (AAC LC, 2.0 ch)", "Language": "English", "LanguageCode": "eng", "TrackNumber": 3 }
|
||||
],
|
||||
"Duration": { "Hours": 0, "Minutes": 52, "Seconds": 47, "Ticks": 542070 },
|
||||
"Index": 1,
|
||||
"Name": "quelle",
|
||||
"SubtitleList": [
|
||||
{ "Format": "text", "Language": "Deutsch (UTF-8)", "LanguageCode": "deu", "SourceName": "UTF-8", "TrackNumber": 1 },
|
||||
{ "Format": "text", "Language": "English (UTF-8)", "LanguageCode": "eng", "SourceName": "UTF-8", "TrackNumber": 2 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
HandBrake has exited.
|
||||
`
|
||||
|
||||
describe('spurenAusScan', () => {
|
||||
it('schneidet das Objekt aus dem Textprotokoll und liest Spuren + Dauer', () => {
|
||||
const s = spurenAusScan(AUSGABE)!
|
||||
expect(s.audio.map((a) => `${a.nr}:${a.lang}`)).toEqual(['1:jpn', '2:deu', '3:eng'])
|
||||
expect(s.untertitel.map((u) => u.lang)).toEqual(['deu', 'eng'])
|
||||
expect(s.dauerS).toBe(52 * 60 + 47)
|
||||
})
|
||||
it('ohne Marke oder mit kaputtem JSON: null, nie ein leerer Befund', () => {
|
||||
expect(spurenAusScan('nichts')).toBeNull()
|
||||
expect(spurenAusScan('JSON Title Set: { "TitleList": [ ')).toBeNull()
|
||||
expect(spurenAusScan('JSON Title Set: { "TitleList": [] }')).toBeNull()
|
||||
})
|
||||
it('buildScanArgs: --scan --json, Titel 1', () => {
|
||||
expect(buildScanArgs('R:\\roh\\a.mkv')).toEqual(['--scan', '--json', '--input', 'R:\\roh\\a.mkv', '--title', '1'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('fehlendeSprachen', () => {
|
||||
it('nennt, was gewünscht ist und nicht drin', () => {
|
||||
const s = spurenAusScan(AUSGABE)!
|
||||
expect(fehlendeSprachen(s, { audio: ['jpn', 'fra'], untertitel: ['deu', 'jpn'] })).toEqual({ audio: ['fra'], untertitel: ['jpn'] })
|
||||
expect(fehlendeSprachen(s, { audio: [], untertitel: [] })).toEqual({ audio: [], untertitel: [] })
|
||||
})
|
||||
})
|
||||
|
||||
describe('MakeMKV-Auswahlregel — reg query lesen', () => {
|
||||
it('findet den Wert in der Ausgabe', () => {
|
||||
const ausgabe = `\r\nHKEY_CURRENT_USER\\Software\\MakeMKV\r\n app_DefaultSelectionString REG_SZ ${RIPPY_REGEL}\r\n\r\n`
|
||||
expect(regelAusQuery(ausgabe)).toBe(RIPPY_REGEL)
|
||||
expect(regelAusQuery('FEHLER: Der angegebene Registrierungsschlüssel oder Wert wurde nicht gefunden.')).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user