feat: run full refresh with EPG rematching
Run full live catalog refreshes through live source sync, complete channel analysis, EPG source refresh, and persisted EPG rematching while keeping check-new incremental. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -339,6 +339,18 @@ function rebuild(database = null, options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fullRebuildOrchestrator(database = null, dependencies = {}) {
|
||||
database ||= defaultDatabase();
|
||||
const syncService = dependencies.syncService || require('./syncService');
|
||||
const sourceRepository = dependencies.sources || require('../db').sources;
|
||||
await syncService.refreshEnabledLiveSources({ rebuild: false });
|
||||
await startRebuild(database, { analyzeAll: true }).promise;
|
||||
await syncService.refreshEnabledEpgSources();
|
||||
const epgSources = await sourceRepository.getByType('epg');
|
||||
epgMatching.rebuildPersistedEpgMatches(database, epgSources);
|
||||
return projectionState(database);
|
||||
}
|
||||
|
||||
async function rebuildWithSignals(database = null, options = {}) {
|
||||
database ||= defaultDatabase();
|
||||
const items = loadProjectionItems(database);
|
||||
@ -389,9 +401,7 @@ function startRebuild(database = null, options = {}) {
|
||||
return { alreadyRunning: false, state: activeState, promise: activeRebuild };
|
||||
}
|
||||
|
||||
function queueRebuild(database = null) {
|
||||
return startRebuild(database, { mode: 'algo' }).promise;
|
||||
}
|
||||
const queueRebuild = (database = null) => startRebuild(database, { mode: 'algo' }).promise;
|
||||
|
||||
function parseData(value) {
|
||||
try { return value ? JSON.parse(value) : {}; } catch { return {}; }
|
||||
@ -435,10 +445,9 @@ function listChannel(channel) {
|
||||
};
|
||||
}
|
||||
|
||||
function getChannelPage({ sourceId = null, includeHidden = false, userId = null, q = '', languages = [], epgSources = [], page = 1, limit = DEFAULT_PAGE_LIMIT }, database = null, dependencies = {}) {
|
||||
function getChannelPage({ sourceId = null, includeHidden = false, userId = null, q = '', languages = [], page = 1, limit = DEFAULT_PAGE_LIMIT }, database = null, dependencies = {}) {
|
||||
database ||= defaultDatabase();
|
||||
const standardCatalog = dependencies.iptvOrgCatalog || iptvOrgCatalog;
|
||||
const epgMatcher = dependencies.epgMatching || epgMatching;
|
||||
const params = [];
|
||||
let sourceFilter = '';
|
||||
if (sourceId !== null) {
|
||||
@ -471,6 +480,24 @@ function getChannelPage({ sourceId = null, includeHidden = false, userId = null,
|
||||
const filtered = serialized.filter(channel =>
|
||||
(!languages.length || languages.includes(channel.language.code)) && matchesSearch(channel, q)
|
||||
);
|
||||
const persistedEpg = new Map(database.prepare(`
|
||||
SELECT logical_channel_id, language_code, source_id, channel_id, match_confidence, data
|
||||
FROM live_epg_matches
|
||||
`).all().map(match => [`${match.logical_channel_id}\0${match.language_code}`, match]));
|
||||
for (const channel of filtered) {
|
||||
const match = persistedEpg.get(`${channel.logicalChannelId}\0${channel.language.code}`);
|
||||
if (!match) continue;
|
||||
let data = {};
|
||||
try { data = match.data ? JSON.parse(match.data) : {}; } catch {}
|
||||
channel.epg = {
|
||||
...channel.epg,
|
||||
...data,
|
||||
sourceId: match.source_id,
|
||||
channelId: match.channel_id,
|
||||
matchConfidence: match.match_confidence,
|
||||
language: channel.language.code
|
||||
};
|
||||
}
|
||||
const bounds = pageBounds(page, limit);
|
||||
const paged = filtered.slice(bounds.offset, bounds.offset + bounds.limit);
|
||||
// Catalog loading must stay bounded: both enrichers perform synchronous SQLite work,
|
||||
@ -483,8 +510,6 @@ function getChannelPage({ sourceId = null, includeHidden = false, userId = null,
|
||||
channel.standardName = match.name;
|
||||
channel.standard = { provider: 'iptv-org', channelId: match.channelId, country: match.country, confidence: match.confidence };
|
||||
}
|
||||
const epgMatch = epgMatcher.findBestMatch(database, channel, epgSources);
|
||||
if (epgMatch) channel.epg = { ...channel.epg, ...epgMatch, language: channel.language.code };
|
||||
return channel;
|
||||
});
|
||||
return {
|
||||
@ -517,7 +542,7 @@ function getChannelVariants({ logicalChannelId, includeHidden = false, userId =
|
||||
}
|
||||
|
||||
function checkNewStreams() {
|
||||
return require('./syncService').syncAll();
|
||||
return require('./syncService').refreshEnabledLiveSources({ rebuild: true });
|
||||
}
|
||||
|
||||
function getChannels(options, database = null) {
|
||||
@ -600,6 +625,7 @@ module.exports = {
|
||||
collectOptionalIdentityHints,
|
||||
displayNameForFingerprint,
|
||||
checkNewStreams,
|
||||
fullRebuildOrchestrator,
|
||||
getChannelPage,
|
||||
getChannelVariants,
|
||||
getChannels,
|
||||
|
||||
Reference in New Issue
Block a user