feat(v5): jede Spur einzeln anhaken — Codec und Kanäle je Tonspur, Untertitel genauso
WAS: Der Auswahl-Dialog zeigt je Titel jede Ton- und Untertitelspur, die der Info-Lauf gemessen hat („German · DTS-HD MA · Surround 5.1", „German · DD · Stereo (Kommentar)", „German · PGS (nur erzwungene)"), vorbelegt wie bisher (je Wunschsprache die erste Tonspur, alle Untertitel der Wunsch- sprachen) — angehakt wird einzeln. Die Untertitel-Vorwahl je Extra ist jetzt eine Spur. Der Parser liest dazu SINFO-Attribute 2 (Anordnung), 22 (Flags) und markiert abgeleitete Spuren (Bit 0x800, an der Kizuna- Disc gemessen): DTS-Kerne werden nicht angeboten, „nur erzwungene"- Untertitel schon. Die Ablage scannt die Roh-Datei und findet die gewählten MakeMKV-Spuren gestuft wieder (Sprache + Codec-Familie + Kanäle → … → Sprache), HandBrake bekommt `--audio 1,3 --subtitle 2,1 --subtitle-default=1`; Fehlendes wird gemeldet, scheitert der Scan, gelten die Sprachen der gewählten Spuren als Liste. MakeMKVs Auswahl- regel lässt Stereo-Doppel jetzt stehen (nur -sel:havecore); Rippys alte Regel wird in der Registry ersetzt, eine fremde bleibt. Dazu F31 (Durchsicht): `--aencoder copy` ohne `--audio-copy-mask` verengt HandBrakeCLI 1.11.2 auf „copy:aac" — AC3/DTS/TrueHD wurden seit 5.0 in AAC umgerechnet. Beide Wege setzen die Maske jetzt ausdrücklich (gemessen 12.09.2026: AC3 bleibt AC3, Passthru-Zeile nennt alle Codecs). WARUM: Commander-Entscheid 12.09.2026 („Jede Spur einzeln anhaken") — bisher ließ sich je Sprache nur „alles oder nichts" wählen, und der Kommentar-Ton fehlte in der Roh-Datei (havemulti). Gemessen am mitgelieferten HandBrakeCLI mit ffmpeg-gebauter Quelle (test/messung.spuren.test.ts, RIPPY_MESSUNG=1): --audio 1,3 → jpn und deu-Kommentar, --subtitle 2,1 --subtitle-default=1 → eng (default) vor deu, --subtitle none → keine Spur. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fc2d16ca38
commit
e7e33e9021
@@ -124,16 +124,26 @@ await schritt('Titel-Lauf liefert drei Titel', async () => {
|
||||
await dialog().getByText('Titel 2', { exact: true }).waitFor()
|
||||
})
|
||||
|
||||
await schritt('Sprachen je Titel: jpn/deu Ton, deu/eng Untertitel als Chips', async () => {
|
||||
await dialog().getByRole('button', { name: /jpn/ }).first().waitFor()
|
||||
await dialog().getByRole('button', { name: /✓ deu/ }).first().waitFor()
|
||||
await schritt('5.7.0: Spuren je Titel einzeln — Codec und Kanäle, der DTS-Kern bleibt unsichtbar', async () => {
|
||||
await dialog().getByLabel('Japanese · DTS-HD MA · Surround 5.1').first().waitFor()
|
||||
await dialog().getByLabel('German · DD · Surround 5.1').first().waitFor()
|
||||
await dialog().getByLabel('German · DD · Stereo (Kommentar)').first().waitFor()
|
||||
await dialog().getByLabel('German · PGS (nur erzwungene)').first().waitFor()
|
||||
if ((await dialog().getByLabel('Japanese · DTS · Surround 5.1').count()) !== 0) throw new Error('der abgeleitete DTS-Kern wird angeboten')
|
||||
// Vorbelegt: je Wunschsprache (deu,eng) die erste Tonspur → nur German DD 5.1;
|
||||
// Untertitel: alle deutschen (auch „nur erzwungene"), englisch nicht.
|
||||
if (!(await dialog().getByLabel('German · DD · Surround 5.1').first().isChecked())) throw new Error('German 5.1 nicht vorbelegt')
|
||||
if (await dialog().getByLabel('German · DD · Stereo (Kommentar)').first().isChecked()) throw new Error('Kommentar-Spur vorbelegt')
|
||||
if (await dialog().getByLabel('Japanese · DTS-HD MA · Surround 5.1').first().isChecked()) throw new Error('Japanisch vorbelegt, obwohl Deutsch da ist')
|
||||
if (!(await dialog().getByLabel('German · PGS (nur erzwungene)').first().isChecked())) throw new Error('erzwungene Untertitel nicht vorbelegt')
|
||||
if (await dialog().getByLabel('English · PGS').first().isChecked()) throw new Error('englische Untertitel vorbelegt')
|
||||
})
|
||||
|
||||
await schritt('Titel 0 bekommt japanischen Ton (deu abwählen, jpn anwählen)', async () => {
|
||||
const chips = dialog().locator('button', { hasText: /^✓ deu$|^deu$/ })
|
||||
await chips.first().click()
|
||||
await dialog().getByRole('button', { name: /^jpn$/ }).first().click()
|
||||
await dialog().getByRole('button', { name: /^✓ jpn$/ }).first().waitFor()
|
||||
await schritt('Titel 0 bekommt japanischen Ton (German 5.1 abhaken, Japanese anhaken)', async () => {
|
||||
await dialog().getByLabel('German · DD · Surround 5.1').first().uncheck()
|
||||
await dialog().getByText('keine Tonspur gewählt — HandBrake nimmt die erste Spur').waitFor()
|
||||
await dialog().getByLabel('Japanese · DTS-HD MA · Surround 5.1').first().check()
|
||||
if ((await dialog().getByText('keine Tonspur gewählt').count()) !== 0) throw new Error('Warnung bleibt trotz japanischer Spur')
|
||||
})
|
||||
|
||||
await schritt('„Hauptinhalt + Extras" wählt beide langen Titel, der Schnipsel bleibt draußen', async () => {
|
||||
@@ -153,7 +163,9 @@ await schritt('5.6.0: Untertitel-Vorwahl erscheint NUR bei Extras, „anderer Fi
|
||||
await rollen.nth(1).selectOption('extra')
|
||||
await dialog().getByText('BEIM ABSPIELEN AN').waitFor()
|
||||
const vorwahl = dialog().locator('select').nth(2)
|
||||
await vorwahl.selectOption('deu')
|
||||
// 5.7.0: Rippys Regel nennt die Spur (japanischer Ton → deutsche
|
||||
// Untertitel), die Optionen sind Spuren — gewählt wird per Nummer (5).
|
||||
await vorwahl.selectOption('5')
|
||||
const knoepfe = await dialog().getByRole('button', { name: 'anderer Film …' }).count()
|
||||
if (knoepfe < 2) throw new Error(`nur ${knoepfe} „anderer Film"-Knöpfe`)
|
||||
await dialog().getByRole('button', { name: 'anderer Film …' }).first().click()
|
||||
@@ -279,22 +291,32 @@ await schritt('Werkzeuge haben Durchsuchen, Allgemein und Update sind eigene Kar
|
||||
})
|
||||
await bild('einstellungen')
|
||||
|
||||
await schritt('Roh-Dateien löschen → „gelöscht"', async () => {
|
||||
await seite.getByRole('button', { name: 'Roh-Dateien löschen' }).first().click()
|
||||
await schritt('Roh-Dateien löschen → Rückfrage → „Ja, löschen" → „gelöscht"', async () => {
|
||||
await seite.getByRole('button', { name: 'Roh-Dateien löschen …' }).first().click()
|
||||
await seite.getByRole('button', { name: 'Ja, löschen' }).first().click()
|
||||
await seite.getByText(/Roh: gelöscht/).first().waitFor()
|
||||
})
|
||||
|
||||
await schritt('5.6.0: Hell-Modus über Einstellungen → Allgemein, data-design wechselt', async () => {
|
||||
await seite.locator('#allgemein').locator('select').first().selectOption('hell')
|
||||
await seite.locator('#allgemein').getByLabel('Erscheinungsbild').selectOption('hell')
|
||||
await seite.locator('html[data-design="hell"]').waitFor()
|
||||
})
|
||||
await bild('hell-modus')
|
||||
|
||||
await schritt('zurück in den Kinosaal (dunkel)', async () => {
|
||||
await seite.locator('#allgemein').locator('select').first().selectOption('dunkel')
|
||||
await seite.locator('#allgemein').getByLabel('Erscheinungsbild').selectOption('dunkel')
|
||||
await seite.locator('html[data-design="dunkel"]').waitFor()
|
||||
})
|
||||
|
||||
await schritt('5.7.0: „Titel lesen — höchstens" steht auf 15 Minuten, 30 lässt sich wählen', async () => {
|
||||
const regler = seite.locator('#allgemein').getByLabel('Titel lesen — höchstens')
|
||||
if ((await regler.inputValue()) !== '15') throw new Error(`Vorgabe ist ${await regler.inputValue()}, nicht 15`)
|
||||
await regler.selectOption('30')
|
||||
// Der Wert geht zum Kern und kommt als Einstellung zurück — erst dann
|
||||
// zeigt das (kontrollierte) Feld 30.
|
||||
await regler.locator('option[value="30"]:checked').waitFor({ state: 'attached' })
|
||||
})
|
||||
|
||||
await schritt('Ereignisse nennen die Kompression', async () => {
|
||||
await seite.getByRole('button', { name: 'Übersicht' }).click()
|
||||
await seite.getByText(/Kompression „/).first().waitFor()
|
||||
@@ -357,6 +379,6 @@ await schritt('Fertig: der Knopf Los geht’s', async () => {
|
||||
})
|
||||
await bild('einrichtung-fertig')
|
||||
|
||||
console.log('KLICK: OK — Speicher, Rippen, Dialog, Sprachen, Folgen, Platz, Rip, Warteschlange, Kompression, Arbeitsordner, Ablage, Verlauf, Bilanz, Roh-Dateien, Einstellungen, Vorwahl, anderer Film, Vorgangs-Leiste, Restzeit, Hell-Modus, Erst-Einrichtung: alles geklickt.')
|
||||
console.log('KLICK: OK — Speicher, Rippen, Dialog, Spuren einzeln, Folgen, Platz, Rip, Warteschlange, Kompression, Arbeitsordner, Ablage, Verlauf, Bilanz, Roh-Dateien, Einstellungen, Vorwahl, anderer Film, Vorgangs-Leiste, Restzeit, Hell-Modus, Erst-Einrichtung: alles geklickt.')
|
||||
await app.close().catch(() => {})
|
||||
process.exit(0)
|
||||
|
||||
Reference in New Issue
Block a user