Files
iptvnator/libs/shared/interfaces/src/lib/vod-source-language.util.spec.ts
T
4grayandClaude Fable 5 d0c79e5bca docs(xtream): cite the measured evidence for the category language gate
The gate's rationale named hypothetical category shapes. On a real
catalog the four it actually turns away are VOD (5,245 movies), KIDS
(1,010), SHOW and WWE — without it the language select offers "VOD" and
"KIDS" as languages. Comments, doc and one spec case only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 01:25:12 +02:00

175 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
isKnownLanguageTag,
titleLanguagePrefix,
unambiguousCategoryLanguage,
vodSourceLanguage,
} from './vod-source-language.util';
describe('titleLanguagePrefix', () => {
it('reads the tag before a pipe, any case', () => {
expect(titleLanguagePrefix('EN| Night of the Living Dead')).toBe('EN');
expect(titleLanguagePrefix('ALB |Some Movie')).toBe('ALB');
expect(titleLanguagePrefix(' ru| Ночь')).toBe('RU');
});
it('reads Cyrillic tags', () => {
expect(titleLanguagePrefix('РУС | Фильм')).toBe('РУС');
expect(titleLanguagePrefix('укр| Фільм')).toBe('УКР');
});
it('reads Unicode pipe lookalikes as the separator', () => {
expect(titleLanguagePrefix('EN │ Movie')).toBe('EN');
expect(titleLanguagePrefix('DE ¦ Der Film')).toBe('DE');
expect(titleLanguagePrefix('FR|Le Film')).toBe('FR');
});
it('reads a bracketed tag at the start', () => {
expect(titleLanguagePrefix('[EN] Movie')).toBe('EN');
expect(titleLanguagePrefix('(ru) Ночь')).toBe('RU');
// A bracket deeper in the title is not a prefix.
expect(titleLanguagePrefix('Movie [EN]')).toBeNull();
});
it('requires the brackets to pair', () => {
// Openers and closers matched independently would accept these.
expect(titleLanguagePrefix('[EN) Movie')).toBeNull();
expect(titleLanguagePrefix('(DE] Film')).toBeNull();
});
it('reads an uppercase tag before a spaced dash, and only that form', () => {
expect(titleLanguagePrefix('EN - Movie')).toBe('EN');
expect(titleLanguagePrefix('РУС - Фильм')).toBe('РУС');
// Lowercase before a dash is a title word ("Up - the movie").
expect(titleLanguagePrefix('Up - the movie')).toBeNull();
// Unspaced dashes are ordinary punctuation.
expect(titleLanguagePrefix('X-Men')).toBeNull();
expect(titleLanguagePrefix('EN-Movie')).toBeNull();
});
it('gates bracket and dash tags to known languages', () => {
// Brackets and dashes are where quality and rip tags live; taking
// them at their word would fabricate an "HD" language that outranks
// and masks a real category-derived one.
expect(titleLanguagePrefix('[HD] Dune')).toBeNull();
expect(titleLanguagePrefix('[UHD] Dune')).toBeNull();
expect(titleLanguagePrefix('[CAM] Dune')).toBeNull();
expect(titleLanguagePrefix('NEW - Dune')).toBeNull();
expect(titleLanguagePrefix('VIP - Dune')).toBeNull();
// The legacy pipe form stays permissive — tightening it would drop
// filter options that work today.
expect(titleLanguagePrefix('SNF| Dune')).toBe('SNF');
});
it('accepts the MULTI marker despite its five letters', () => {
expect(titleLanguagePrefix('MULTI | Movie')).toBe('MULTI');
expect(titleLanguagePrefix('Multi| Movie')).toBe('MULTI');
});
it('rejects titles whose separator is not a language marker', () => {
// Five letters is a word, not a language code.
expect(titleLanguagePrefix('NIGHT| of something')).toBeNull();
expect(titleLanguagePrefix('Night of the Living Dead')).toBeNull();
expect(titleLanguagePrefix('4K| Movie')).toBeNull();
expect(titleLanguagePrefix(undefined)).toBeNull();
expect(titleLanguagePrefix('')).toBeNull();
});
});
describe('isKnownLanguageTag', () => {
it('accepts assigned two-letter ISO codes in any case', () => {
expect(isKnownLanguageTag('EN')).toBe(true);
expect(isKnownLanguageTag('de')).toBe(true);
expect(isKnownLanguageTag('uk')).toBe(true);
});
it('rejects unassigned two-letter tokens', () => {
expect(isKnownLanguageTag('HD')).toBe(false);
expect(isKnownLanguageTag('XX')).toBe(false);
});
it('accepts curated long tags, Latin and Cyrillic', () => {
expect(isKnownLanguageTag('ENG')).toBe(true);
expect(isKnownLanguageTag('DEU')).toBe(true);
expect(isKnownLanguageTag('LAT')).toBe(true);
expect(isKnownLanguageTag('РУС')).toBe(true);
expect(isKnownLanguageTag('MULTI')).toBe(true);
});
it('rejects the content-type prefixes categories actually use', () => {
// The four the gate turns away most often on a real catalog; without
// it the language select offers "VOD" and "KIDS".
for (const tag of ['VOD', 'KIDS', 'SHOW', 'WWE']) {
expect(isKnownLanguageTag(tag)).toBe(false);
}
});
it('rejects everyday category words that are real ISO 639-3 codes', () => {
// `new`, `top` and `hot` are assigned in ISO 639-3, which is exactly
// why validation is curated instead of registry-driven.
expect(isKnownLanguageTag('NEW')).toBe(false);
expect(isKnownLanguageTag('TOP')).toBe(false);
expect(isKnownLanguageTag('HOT')).toBe(false);
expect(isKnownLanguageTag('VIP')).toBe(false);
expect(isKnownLanguageTag('KIDS')).toBe(false);
});
});
describe('unambiguousCategoryLanguage', () => {
it('reads the language every prefixed category agrees on', () => {
expect(
unambiguousCategoryLanguage(['EN | Netflix', 'EN | Action'])
).toBe('EN');
});
it('lets unprefixed categories abstain rather than veto', () => {
expect(
unambiguousCategoryLanguage(['EN | Netflix', 'Netflix 4K'])
).toBe('EN');
});
it('yields nothing on a conflict', () => {
expect(
unambiguousCategoryLanguage(['EN | Netflix', 'DE | Cinema'])
).toBeNull();
});
it('rejects category prefixes that are not languages', () => {
expect(unambiguousCategoryLanguage(['NEW | 2024'])).toBeNull();
expect(unambiguousCategoryLanguage(['TOP | 250'])).toBeNull();
expect(unambiguousCategoryLanguage(['VIP | Cinema'])).toBeNull();
// ...while a real language beside them still reads through.
expect(
unambiguousCategoryLanguage(['NEW | 2024', 'DE | Apple TV'])
).toBe('DE');
});
it('handles empty and missing input', () => {
expect(unambiguousCategoryLanguage([])).toBeNull();
expect(unambiguousCategoryLanguage(null)).toBeNull();
expect(unambiguousCategoryLanguage(undefined)).toBeNull();
expect(unambiguousCategoryLanguage([null, ''])).toBeNull();
});
});
describe('vodSourceLanguage', () => {
it('prefers the title prefix over the category language', () => {
expect(
vodSourceLanguage({
rawTitle: 'RU| Movie',
categoryLanguage: 'EN',
})
).toBe('RU');
});
it('falls back to the category language when the title says nothing', () => {
expect(
vodSourceLanguage({ rawTitle: 'Movie', categoryLanguage: 'EN' })
).toBe('EN');
});
it('yields nothing when neither side knows', () => {
expect(vodSourceLanguage({ rawTitle: 'Movie' })).toBeNull();
expect(vodSourceLanguage({})).toBeNull();
});
});