feat: precompute stream grouping during source sync (#13)
Move variant grouping work out of Live TV rendering into the catalog pipeline: a liveProjectionService builds the logical channel projection (schema in liveProjectionSchema) whenever a source is added, synced or modified (name change, new address), and the projection is served through a /live route. ChannelList now consumes the precomputed projection via a liveChannelProjection client service, recalculating only when the catalog changes. Cover projection building, incremental recompute and client consumption with tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
34
test/liveChannelProjection.test.js
Normal file
34
test/liveChannelProjection.test.js
Normal file
@ -0,0 +1,34 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const projection = require('../public/js/services/liveChannelProjection.js');
|
||||
|
||||
test('maps projected logical channels to the frontend variant format', () => {
|
||||
const response = {
|
||||
projection: { status: 'success', stale: false },
|
||||
channels: [{
|
||||
id: 'logical:one', fingerprint: 'news', displayName: 'News',
|
||||
variants: [{
|
||||
id: 42, sourceId: 7, name: 'News HD', categoryId: 'News',
|
||||
streamIcon: 'logo.png', streamUrl: 'https://stream.test/live',
|
||||
tvgId: 'news.fr', isFavorite: true, isHidden: true
|
||||
}]
|
||||
}]
|
||||
};
|
||||
const mapped = projection.mapResponse(response, [{ id: 7, type: 'm3u', name: 'Local' }]);
|
||||
assert.deepEqual(mapped.channels[0], {
|
||||
id: '42', sourceId: 7, name: 'News HD', categoryId: 'News',
|
||||
streamIcon: 'logo.png', streamUrl: 'https://stream.test/live', tvgId: 'news.fr',
|
||||
isFavorite: true, isHidden: true, logicalId: 'logical:one',
|
||||
logicalFingerprint: 'news', logicalDisplayName: 'News',
|
||||
streamId: '42', tvgLogo: 'logo.png',
|
||||
url: 'https://stream.test/live', groupTitle: 'News', sourceType: 'm3u', sourceName: 'Local'
|
||||
});
|
||||
assert.equal(mapped.favorites.has('7:42'), true);
|
||||
assert.equal(mapped.hiddenItems.has('channel:7:42'), true);
|
||||
});
|
||||
|
||||
test('rejects stale projections so ChannelList can use its legacy fallback', () => {
|
||||
assert.equal(projection.canUse({ projection: { stale: true }, channels: [] }), false);
|
||||
assert.equal(projection.canUse({ projection: { stale: false }, channels: [] }), true);
|
||||
assert.equal(projection.canUse(null), false);
|
||||
});
|
||||
Reference in New Issue
Block a user