feat(live): add language-aware flexible channel search (#23)
Add backend language detection, flexible live channel search, iptv-org catalog caching, and protected built-in EPG source registration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
42
test/t23Backend.test.js
Normal file
42
test/t23Backend.test.js
Normal file
@ -0,0 +1,42 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const Database = require('better-sqlite3');
|
||||
const { detectLanguage } = require('../server/services/channelLanguage');
|
||||
const { matchesSearch, normalizeSearch } = require('../server/services/flexibleChannelSearch');
|
||||
const { ensureBuiltinSources } = require('../server/services/builtinEpgRegistry');
|
||||
const iptvOrg = require('../server/services/iptvOrgCatalogService');
|
||||
const { LIVE_PROJECTION_SCHEMA_SQL } = require('../server/db/liveProjectionSchema');
|
||||
|
||||
test('flexible search ignores accents, punctuation, case and simple plurals', () => {
|
||||
const channel = { displayName: 'beIN Sports 1', variants: [{ name: 'BéIN SPORTS 1 HD' }] };
|
||||
for (const query of ['Bein Sport 1', 'bein sports 1', 'beIN Sport 1']) assert.equal(matchesSearch(channel, query), true);
|
||||
assert.deepEqual(normalizeSearch('Chaînes-Sports'), ['chaine', 'sport']);
|
||||
});
|
||||
|
||||
test('backend language detection uses und and separates explicit languages', () => {
|
||||
assert.equal(detectLanguage({ name: 'Generic Sports' }).code, 'und');
|
||||
assert.equal(detectLanguage({ name: '|FR| Sports One' }).code, 'fr');
|
||||
assert.equal(detectLanguage({ name: '[UK] Sports One' }).code, 'en');
|
||||
});
|
||||
|
||||
test('built-in EPG registry is idempotent and protected while remaining disabled by default', () => {
|
||||
const data = ensureBuiltinSources({ sources: [], nextId: 1 });
|
||||
ensureBuiltinSources(data);
|
||||
assert.equal(data.sources.length, 2);
|
||||
assert.ok(data.sources.every(source => source.type === 'epg' && source.readonly && !source.removable && !source.enabled));
|
||||
});
|
||||
|
||||
test('iptv-org adapter refreshes a persistent cache and matches aliases by language', async () => {
|
||||
const db = new Database(':memory:');
|
||||
db.exec(`CREATE TABLE playlist_items (id TEXT PRIMARY KEY, logical_channel_id TEXT, grouping_fingerprint TEXT);`);
|
||||
db.exec(LIVE_PROJECTION_SCHEMA_SQL);
|
||||
const payloads = {
|
||||
'channels.json': [{ id: 'BeInSports1.fr', name: 'beIN Sports 1', alt_names: ['Bein Sport 1'], country: 'FR' }],
|
||||
'feeds.json': [{ channel: 'BeInSports1.fr', languages: ['fr'] }]
|
||||
};
|
||||
await iptvOrg.refresh(db, async url => ({ ok: true, json: async () => payloads[url.split('/').pop()] }));
|
||||
const match = iptvOrg.findMatch(db, { displayName: 'Bein Sport 1', language: { code: 'fr' }, variants: [] });
|
||||
assert.equal(match.channelId, 'BeInSports1.fr');
|
||||
assert.equal(match.name, 'beIN Sports 1');
|
||||
assert.equal(db.prepare("SELECT item_count FROM iptv_org_cache_state WHERE resource = 'catalog'").get().item_count, 1);
|
||||
});
|
||||
Reference in New Issue
Block a user