Files
netfelix-audio-fix/server/services/language-utils.ts
T
felixfoertsch 9d65dd12be
Build and Push Docker Image / build (push) Successful in 2m10s
pipeline ux: actionable errors, inbox sorting, danger stop buttons, overlapping checkmarks
- clickable error count in header shows file names + error messages
- inbox sort dropdown (scan time / name, asc / desc)
- inbox movies no longer minimal (show available badges)
- stop buttons use solid danger style, descriptive labels (Stop Scan, Stop Job, Stop Sorting)
- double checkmarks overlap like WhatsApp read receipts
- processInbox logs start/completion to stdout for Docker visibility
- fix byTitle in language-resolver test, bump to 2026.04.21.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 08:58:08 +02:00

93 lines
1.9 KiB
TypeScript

// ISO 639-1 (2-letter) → ISO 639-2/B (3-letter)
const ISO_1_TO_2: Record<string, string> = {
en: "eng",
de: "deu",
es: "spa",
fr: "fra",
it: "ita",
pt: "por",
ja: "jpn",
ko: "kor",
zh: "zho",
ar: "ara",
ru: "rus",
nl: "nld",
sv: "swe",
no: "nor",
da: "dan",
fi: "fin",
pl: "pol",
tr: "tur",
th: "tha",
hi: "hin",
hu: "hun",
cs: "ces",
ro: "ron",
el: "ell",
he: "heb",
fa: "fas",
uk: "ukr",
id: "ind",
ca: "cat",
nb: "nob",
nn: "nno",
is: "isl",
hr: "hrv",
sk: "slk",
bg: "bul",
sr: "srp",
sl: "slv",
lv: "lav",
lt: "lit",
et: "est",
vi: "vie",
ms: "msa",
ta: "tam",
te: "tel",
};
// ISO 639-2/T → ISO 639-2/B normalization + common aliases
const LANG_ALIASES: Record<string, string> = {
ger: "deu",
chi: "zho",
fre: "fra",
dut: "nld",
gre: "ell",
heb: "heb",
per: "fas",
rum: "ron",
may: "msa",
tib: "bod",
bur: "mya",
cze: "ces",
slo: "slk",
geo: "kat",
ice: "isl",
arm: "hye",
baq: "eus",
alb: "sqi",
mac: "mkd",
wel: "cym",
};
export function normalizeLanguage(lang: string): string {
const lower = lang.toLowerCase().trim();
if (ISO_1_TO_2[lower]) return ISO_1_TO_2[lower];
return LANG_ALIASES[lower] ?? lower;
}
const DUB_TITLE_HINTS = /(dub|dubb|synchro|commentary|director)/i;
/**
* Guess original language from audio streams by looking at the default track.
* Heuristic: prefer the default audio track, skip dubs/commentary, fall back to first.
*/
export function guessOriginalLanguage(
audioStreams: { language: string | null; title: string | null; isDefault: number }[],
): string | null {
if (audioStreams.length === 0) return null;
const notDub = (s: { title: string | null }) => !s.title || !DUB_TITLE_HINTS.test(s.title);
const pick = audioStreams.find((s) => s.isDefault && notDub(s)) ?? audioStreams.find(notDub) ?? audioStreams[0];
return pick.language ? normalizeLanguage(pick.language) : null;
}