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>
101 lines
4.9 KiB
TypeScript
101 lines
4.9 KiB
TypeScript
// MakeMKVs Spur-Auswahlregel (5.4.0) — damit ALLE Sprachen in der
|
||
// Roh-Datei landen, die der Auswahl-Dialog anbietet.
|
||
//
|
||
// Der Befund: Der Info-Lauf zeigt jede Tonspur der Disc — aber ob sie in
|
||
// die MKV kommt, entscheidet MakeMKVs „default selection rule". Die Doku
|
||
// (forum.makemkv.com, Thema 4386, am 01.09.2026 nachgelesen — Regel D)
|
||
// nennt als Regel des Standard-Profils
|
||
//
|
||
// -sel:all,+sel:(favlang|nolang),-sel:(havemulti|havecore),=100:all,-10:favlang
|
||
//
|
||
// mit: favlang = „matches favorite languages, always matches if no
|
||
// favorite language is set" · havemulti = „track is mono/stereo and there
|
||
// is a multi-channel track in same language" · havecore = „this track is
|
||
// hd track with core audio" · +sel/-sel = wählen/abwählen · =N = Gewicht.
|
||
//
|
||
// Solange KEINE Vorzugssprache gesetzt ist, nimmt MakeMKV also alles
|
||
// (bis auf die Stereo-Doppel und die DTS-Kerne). Sobald jemand in MakeMKVs
|
||
// Einstellungen „Deutsch" wählt, fielen japanischer und englischer Ton
|
||
// STILL weg — und der Dialog böte Sprachen an, die nicht in der Datei
|
||
// sind. Rippy setzt deshalb seine eigene Regel, die sprachunabhängig
|
||
// alles behält, und zwar NUR, wenn noch keine gesetzt ist (wer eine
|
||
// eigene hat, behält sie — wie bei app_UpdateEnable in schluessel.ts).
|
||
// Abgelegt wird wie der Schlüssel in HKCU\Software\MakeMKV (Windows liest
|
||
// dort, die settings.conf ist der Linux-Weg).
|
||
//
|
||
// 5.7.0: Seit der Dialog jede Spur einzeln anbietet, dürfen auch die
|
||
// Stereo-Doppel bleiben (havemulti — „Deutsch · DD · 2.0 (Kommentar)"
|
||
// neben „Deutsch · DTS-HD MA · 5.1"): Nur die abgeleiteten DTS-Kerne
|
||
// (havecore) fallen weg, die zeigt der Dialog gar nicht erst. Stand
|
||
// Rippys ALTE Regel in der Registry, wird sie ersetzt; eine fremde bleibt.
|
||
import { spawnSync } from 'node:child_process'
|
||
|
||
export const REGISTRY_PFAD = 'HKCU\\Software\\MakeMKV'
|
||
export const REGEL_NAME = 'app_DefaultSelectionString'
|
||
/** Alles behalten, nur die Kerne weg — sprachunabhängig (5.7.0). */
|
||
export const RIPPY_REGEL = '-sel:all,+sel:all,-sel:havecore,=100:all'
|
||
/** Rippys frühere Regeln (5.4.0–5.6.1) — werden beim Start ersetzt. */
|
||
export const RIPPY_REGELN_ALT: readonly string[] = ['-sel:all,+sel:all,-sel:(havemulti|havecore),=100:all']
|
||
|
||
export interface SpurauswahlStand {
|
||
/** 'gesetzt' (von Rippy, jetzt) | 'eigen' (der Nutzer hat eine eigene) |
|
||
* 'rippy' (Rippys Regel steht schon) | 'fehler' */
|
||
stand: 'gesetzt' | 'eigen' | 'rippy' | 'fehler'
|
||
regel: string
|
||
text: string
|
||
}
|
||
|
||
/** Was mit einer vorgefundenen Regel geschieht (pur, testbar):
|
||
* 'rippy' = steht schon · 'ersetzen' = Rippys alte Regel · 'eigen' =
|
||
* fremd, bleibt · 'setzen' = keine da. */
|
||
export function regelUrteil(bisher: string | null): 'rippy' | 'ersetzen' | 'eigen' | 'setzen' {
|
||
if (bisher === null || bisher.length === 0) return 'setzen'
|
||
if (bisher === RIPPY_REGEL) return 'rippy'
|
||
if (RIPPY_REGELN_ALT.includes(bisher)) return 'ersetzen'
|
||
return 'eigen'
|
||
}
|
||
|
||
function reg(args: string[]): { ok: boolean; ausgabe: string } {
|
||
const ergebnis = spawnSync('reg', args, { windowsHide: true, timeout: 15_000, encoding: 'utf8' })
|
||
return { ok: ergebnis.status === 0, ausgabe: (ergebnis.stdout ?? '') + (ergebnis.stderr ?? '') }
|
||
}
|
||
|
||
/** Den Wert aus `reg query`-Ausgabe lesen (pur, testbar):
|
||
* „ app_DefaultSelectionString REG_SZ -sel:all,…" */
|
||
export function regelAusQuery(ausgabe: string): string | null {
|
||
const treffer = new RegExp(`${REGEL_NAME}\\s+REG_SZ\\s+(.*)$`, 'm').exec(ausgabe)
|
||
return treffer === null ? null : treffer[1].trim()
|
||
}
|
||
|
||
/** Sicherstellen, dass eine Regel steht, die alle Sprachen behält. */
|
||
export function spurauswahlSicherstellen(): SpurauswahlStand {
|
||
if (process.platform !== 'win32') {
|
||
return { stand: 'fehler', regel: '', text: 'Nur unter Windows (Registry).' }
|
||
}
|
||
const vorhanden = reg(['query', REGISTRY_PFAD, '/v', REGEL_NAME])
|
||
const bisher = vorhanden.ok ? regelAusQuery(vorhanden.ausgabe) : null
|
||
const urteil = regelUrteil(bisher)
|
||
if (urteil === 'rippy') {
|
||
return { stand: 'rippy', regel: bisher ?? '', text: 'MakeMKV behält alle Spuren (Rippys Auswahlregel steht).' }
|
||
}
|
||
if (urteil === 'eigen') {
|
||
return {
|
||
stand: 'eigen',
|
||
regel: bisher ?? '',
|
||
text: `MakeMKV hat eine eigene Auswahlregel („${bisher}") — Rippy lässt sie stehen. Fehlen Spuren in der Roh-Datei, liegt es daran.`,
|
||
}
|
||
}
|
||
const gesetzt = reg(['add', REGISTRY_PFAD, '/v', REGEL_NAME, '/t', 'REG_SZ', '/d', RIPPY_REGEL, '/f'])
|
||
if (!gesetzt.ok) {
|
||
return { stand: 'fehler', regel: '', text: `Auswahlregel nicht setzbar: ${gesetzt.ausgabe.trim().slice(0, 160)}` }
|
||
}
|
||
return {
|
||
stand: 'gesetzt',
|
||
regel: RIPPY_REGEL,
|
||
text:
|
||
urteil === 'ersetzen'
|
||
? 'MakeMKV-Auswahlregel erneuert: jede Spur kommt in die Roh-Datei, auch Stereo-Fassungen und Kommentare (nur DTS-Kerne nicht).'
|
||
: 'MakeMKV-Auswahlregel gesetzt: jede Spur kommt in die Roh-Datei (nur DTS-Kerne nicht).',
|
||
}
|
||
}
|