feat: persist incremental live channel analysis
Persist live channel language metadata across background projection rebuilds and target Local AI identity analysis to newly detected streams unless a manual full analysis is requested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -8,6 +8,18 @@ const liveProjection = require('./liveProjectionService');
|
||||
// Sync tracking
|
||||
const activeSyncs = new Set(); // sourceId
|
||||
|
||||
async function rebuildLiveProjection(newIds) {
|
||||
const currentSettings = await settings.get();
|
||||
const mode = currentSettings.languageDetectionMode;
|
||||
if (newIds.size > 0 && (mode === 'laya' || mode === 'hybrid')) {
|
||||
return liveProjection.startRebuild(undefined, {
|
||||
mode,
|
||||
scopeItemIds: [...newIds]
|
||||
}).promise;
|
||||
}
|
||||
return liveProjection.queueRebuild();
|
||||
}
|
||||
|
||||
class SyncService {
|
||||
constructor() {
|
||||
this.lastSyncTime = null; // Track when global sync last completed
|
||||
@ -183,8 +195,8 @@ class SyncService {
|
||||
// 2. Live Streams
|
||||
console.log(`[Sync] Fetching Live Streams for ${source.name}`);
|
||||
const liveStreams = await api.getLiveStreams();
|
||||
await this.saveStreams(source.id, 'live', liveStreams);
|
||||
await liveProjection.queueRebuild();
|
||||
const { newIds } = await this.saveStreams(source.id, 'live', liveStreams);
|
||||
await rebuildLiveProjection(newIds);
|
||||
|
||||
// 3. VOD Categories
|
||||
console.log(`[Sync] Fetching VOD Categories for ${source.name}`);
|
||||
@ -259,15 +271,17 @@ class SyncService {
|
||||
* @param {string} type - Type of items (live, movie, series)
|
||||
* @param {Array} items - Items to save
|
||||
* @param {Object} options - Options { skipPurge: boolean }
|
||||
* @returns {Set} Set of synced IDs (for external purge if skipPurge was true)
|
||||
* @returns {{ syncedIds: Set<string>, newIds: Set<string> }} Synced and newly inserted IDs
|
||||
*/
|
||||
async saveStreams(sourceId, type, items, options = {}) {
|
||||
if (!items || items.length === 0) return new Set();
|
||||
if (!items || items.length === 0) return { syncedIds: new Set(), newIds: new Set() };
|
||||
const db = getDb();
|
||||
const { skipPurge = false } = options;
|
||||
|
||||
// Collect all IDs we're syncing
|
||||
const syncedIds = new Set();
|
||||
const newIds = new Set();
|
||||
const existingItem = db.prepare('SELECT 1 FROM playlist_items WHERE id = ?');
|
||||
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO playlist_items (
|
||||
@ -316,6 +330,7 @@ class SyncService {
|
||||
|
||||
const id = `${sourceId}:${itemId}`;
|
||||
syncedIds.add(id);
|
||||
if (!existingItem.get(id)) newIds.add(id);
|
||||
|
||||
stmt.run(
|
||||
id,
|
||||
@ -349,7 +364,7 @@ class SyncService {
|
||||
}
|
||||
|
||||
console.log(`[Sync] Saved ${items.length} ${type} items`);
|
||||
return syncedIds;
|
||||
return { syncedIds, newIds };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -511,6 +526,7 @@ class SyncService {
|
||||
|
||||
const allGroups = new Set();
|
||||
const allSyncedIds = new Set(); // Collect IDs across all batches
|
||||
const allNewIds = new Set();
|
||||
let totalChannels = 0;
|
||||
let batchCount = 0;
|
||||
|
||||
@ -530,8 +546,9 @@ class SyncService {
|
||||
|
||||
// Save this batch immediately (skip purge - we'll do it at the end)
|
||||
if (playlistItems.length > 0) {
|
||||
const batchIds = await this.saveStreams(source.id, 'live', playlistItems, { skipPurge: true });
|
||||
batchIds.forEach(id => allSyncedIds.add(id));
|
||||
const { syncedIds, newIds } = await this.saveStreams(source.id, 'live', playlistItems, { skipPurge: true });
|
||||
syncedIds.forEach(id => allSyncedIds.add(id));
|
||||
newIds.forEach(id => allNewIds.add(id));
|
||||
totalChannels += playlistItems.length;
|
||||
}
|
||||
|
||||
@ -561,7 +578,7 @@ class SyncService {
|
||||
}));
|
||||
|
||||
await this.saveCategories(source.id, 'live', categories);
|
||||
await liveProjection.queueRebuild();
|
||||
await rebuildLiveProjection(allNewIds);
|
||||
console.log(`[Sync] M3U sync complete for ${source.name}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user