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
@@ -134,8 +134,18 @@ export interface StreamInfo {
|
||||
codec: string
|
||||
kanaele: string
|
||||
beschreibung: string
|
||||
/** Attribut 2: „Surround 5.1", „Stereo" (5.7.0). */
|
||||
layout: string
|
||||
/** Attribut 22: Flags. Bit 0x800 heißt „abgeleitet" — an der Kizuna-Disc
|
||||
* gemessen (03.09.2026): 2304 (0x900) am DTS-Kern der DTS-HD-Spur, 6144
|
||||
* (0x1800) an der „nur erzwungene"-Fassung eines Untertitels, 1024 und 0
|
||||
* an den vollen Spuren (5.7.0). */
|
||||
flags: number
|
||||
}
|
||||
|
||||
/** Bit 0x800 in Attribut 22: eine von MakeMKV abgeleitete Spur. */
|
||||
export const STREAM_FLAG_ABGELEITET = 0x800
|
||||
|
||||
export interface TitelStreams {
|
||||
audio: StreamInfo[]
|
||||
untertitel: StreamInfo[]
|
||||
@@ -160,17 +170,19 @@ export function parseStreamInfo(ausgabe: string): Map<number, TitelStreams> {
|
||||
}
|
||||
let eintrag = streams.get(sNr)
|
||||
if (eintrag === undefined) {
|
||||
eintrag = { nr: sNr, typ: '', typCode: 0, lang: '', sprache: '', codec: '', kanaele: '', beschreibung: '' }
|
||||
eintrag = { nr: sNr, typ: '', typCode: 0, lang: '', sprache: '', codec: '', kanaele: '', beschreibung: '', layout: '', flags: 0 }
|
||||
streams.set(sNr, eintrag)
|
||||
}
|
||||
if (attr === 1) {
|
||||
eintrag.typ = wert
|
||||
eintrag.typCode = code
|
||||
}
|
||||
else if (attr === 2) eintrag.layout = wert
|
||||
else if (attr === 3) eintrag.lang = wert
|
||||
else if (attr === 4) eintrag.sprache = wert
|
||||
else if (attr === 6) eintrag.codec = wert
|
||||
else if (attr === 14) eintrag.kanaele = wert
|
||||
else if (attr === 22 && /^\d+$/.test(wert)) eintrag.flags = Number(wert)
|
||||
else if (attr === 30) eintrag.beschreibung = wert
|
||||
}
|
||||
|
||||
@@ -192,8 +204,8 @@ export function parseStreamInfo(ausgabe: string): Map<number, TitelStreams> {
|
||||
|
||||
// EINE Definition für Kern und Fenster (5.4.0): Der Auswahl-Dialog zeigt
|
||||
// die Sprachen je Titel — deshalb lebt der Typ in gemeinsam/.
|
||||
import type { SprachEintrag } from '../../gemeinsam/nachrichten'
|
||||
export type { SprachEintrag }
|
||||
import type { SprachEintrag, SpurAngabe } from '../../gemeinsam/nachrichten'
|
||||
export type { SprachEintrag, SpurAngabe }
|
||||
|
||||
/** Welche Sprachen hat die DISC insgesamt? Über alle Titel vereinigt,
|
||||
* Reihenfolge stabil (wie auf der Disc). */
|
||||
@@ -219,6 +231,24 @@ export function sprachenZusammenfassen(streamsJeTitel: Map<number, TitelStreams>
|
||||
return { audio: sammeln('audio'), untertitel: sammeln('untertitel') }
|
||||
}
|
||||
|
||||
/** Jede Spur EINES Titels als SpurAngabe (5.7.0, für den Auswahl-Dialog):
|
||||
* Ton und Untertitel getrennt, in Disc-Reihenfolge, abgeleitete Spuren
|
||||
* markiert. Ohne Streams leer. */
|
||||
export function spurenFuerTitel(streams: TitelStreams | undefined): { audio: SpurAngabe[]; untertitel: SpurAngabe[] } {
|
||||
const angabe = (s: StreamInfo): SpurAngabe => ({
|
||||
nr: s.nr,
|
||||
lang: s.lang,
|
||||
sprache: s.sprache.length > 0 ? s.sprache : s.lang,
|
||||
codec: s.codec,
|
||||
kanaele: s.kanaele,
|
||||
layout: s.layout,
|
||||
beschreibung: s.beschreibung,
|
||||
abgeleitet: (s.flags & STREAM_FLAG_ABGELEITET) !== 0,
|
||||
})
|
||||
if (streams === undefined) return { audio: [], untertitel: [] }
|
||||
return { audio: streams.audio.map(angabe), untertitel: streams.untertitel.map(angabe) }
|
||||
}
|
||||
|
||||
/** Die Sprachen EINES Titels (5.4.0, für den Auswahl-Dialog) — dieselbe
|
||||
* Zusammenfassung wie oben, nur auf einen Titel beschränkt. Ohne Streams
|
||||
* (Titel unbekannt) leer, nicht erfunden. */
|
||||
|
||||
Reference in New Issue
Block a user