Fix: zu weite Deutsch-Erkennung konnte falsche Tonspur behalten

- isGermanStream: Titel-Fallback nur noch ganze Woerter (german/deutsch); die
  2-3-Buchstaben-Codes ger/deu sind im freien Titel-Text mehrdeutig und konnten
  die falsche Spur als "deutsch" picken (und damit die echte deutsche loeschen).
  Der Sprach-Tag-Check (ger/deu/de) bleibt unveraendert.
- looksLikeGermanRelease: 'dubbed' entfernt — ein nacktes "Dubbed" kann ein
  italienischer/franzoesischer Dub sein und darf den German-first-Fallback nicht
  ausloesen. Explizite german/deutsch-Tokens reichen.
- 2 Negativtests (3-Letter-Titel-Code, nicht-deutscher Dub).
This commit is contained in:
Sucukdeluxe 2026-06-08 22:31:34 +02:00
parent b71866c3dc
commit 272a41a4a7
2 changed files with 19 additions and 4 deletions

View File

@ -89,10 +89,11 @@ export function isRemuxableVideoFile(fileName: string): boolean {
// True when the release name explicitly marks it as a German release. Used in
// tag mode to fall back to the first audio track (German-first scene convention)
// when the audio language tags are wrong (a German dub mislabeled "eng"), instead
// of skipping. Deliberately requires an explicit german/deutsch/dubbed token —
// the ".DL." marker alone (present on every processed file) is not enough.
// of skipping. Deliberately requires an explicit german/deutsch token — the
// ".DL." marker alone (present on every processed file) is not enough, and a bare
// "dubbed" can mean an Italian/French dub, so it must NOT flag a German release.
export function looksLikeGermanRelease(fileName: string): boolean {
return /(^|[._\s-])(german|deutsch|dubbed)([._\s-]|$)/i.test(fileName);
return /(^|[._\s-])(german|deutsch)([._\s-]|$)/i.test(fileName);
}
function isGermanStream(stream: ProbedAudioStream): boolean {
@ -100,8 +101,11 @@ function isGermanStream(stream: ProbedAudioStream): boolean {
if (["ger", "deu", "de", "german", "deutsch"].includes(lang)) {
return true;
}
// Free-text title fallback (used when the language tag is missing). Full words
// only — the 2-3 letter codes ger/deu are too ambiguous in a title and would
// pick the wrong track to keep (which then deletes the real German one).
const title = (stream.title || "").toLowerCase();
return /\b(german|deutsch|ger|deu)\b/.test(title);
return /\b(german|deutsch)\b/.test(title);
}
// Decide which audio track to keep. Safety invariant: only ever choose to remux

View File

@ -85,6 +85,13 @@ describe("pickAudioTrack", () => {
expect(d).toMatchObject({ action: "remux", audioRelIndex: 1 });
});
it("tag mode does NOT treat an ambiguous 3-letter title code as German (no false-positive pick)", () => {
// Two untagged tracks whose titles are only "Ger"/"Deu" must not be mistaken
// for a German track; with no real German signal this falls back to first.
const d = pickAudioTrack([{ language: "", title: "Ger" }, { language: "", title: "Deu" }], "tag");
expect(d).toMatchObject({ action: "remux", audioRelIndex: 0, reason: "fallback-first-untagged" });
});
it("tag mode with single German -> single (no remux)", () => {
expect(pickAudioTrack([ger], "tag")).toMatchObject({ action: "single" });
});
@ -125,6 +132,10 @@ describe("looksLikeGermanRelease", () => {
expect(looksLikeGermanRelease("Show.S01E01.DL.720p.x264.mkv")).toBe(false);
expect(looksLikeGermanRelease("Show.S01E01.MULTi.1080p.mkv")).toBe(false);
});
it("does not flag a non-German dub as a German release (bare 'Dubbed' is ambiguous)", () => {
expect(looksLikeGermanRelease("Movie.2020.ITALIAN.Dubbed.DL.1080p.mkv")).toBe(false);
expect(looksLikeGermanRelease("Movie.2020.FRENCH.DUBBED.DL.720p.mkv")).toBe(false);
});
});
describe("parseFfprobeAudioStreams", () => {