Implemented virutal scrolling for epg, optimized database batching, moved sync timer to server
This commit is contained in:
+4
-2
@@ -79,7 +79,9 @@ app.listen(PORT, async () => {
|
||||
console.log(`NodeCast TV server running on http://localhost:${PORT}`);
|
||||
|
||||
// Trigger background sync with delay to allow server to settle
|
||||
setTimeout(() => {
|
||||
syncService.syncAll().catch(console.error);
|
||||
setTimeout(async () => {
|
||||
await syncService.syncAll().catch(console.error);
|
||||
// Start the server-side sync timer after initial sync
|
||||
await syncService.startSyncTimer().catch(console.error);
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { settings, getDefaultSettings } = require('../db');
|
||||
const syncService = require('../services/syncService');
|
||||
|
||||
/**
|
||||
* Get all settings
|
||||
@@ -24,6 +25,12 @@ router.put('/', async (req, res) => {
|
||||
try {
|
||||
const updates = req.body;
|
||||
const updatedSettings = await settings.update(updates);
|
||||
|
||||
// If sync interval changed, restart the server-side sync timer
|
||||
if (updates.epgRefreshInterval !== undefined) {
|
||||
syncService.restartSyncTimer().catch(console.error);
|
||||
}
|
||||
|
||||
res.json(updatedSettings);
|
||||
} catch (err) {
|
||||
console.error('Error updating settings:', err);
|
||||
@@ -53,4 +60,16 @@ router.get('/defaults', (req, res) => {
|
||||
res.json(getDefaultSettings());
|
||||
});
|
||||
|
||||
/**
|
||||
* Get sync status (last sync time)
|
||||
* GET /api/settings/sync-status
|
||||
*/
|
||||
router.get('/sync-status', (req, res) => {
|
||||
const lastSyncTime = syncService.getLastSyncTime();
|
||||
res.json({
|
||||
lastSyncTime: lastSyncTime ? lastSyncTime.toISOString() : null
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
@@ -185,4 +185,17 @@ router.post('/:id/test', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Global Sync - sync all enabled sources
|
||||
router.post('/sync-all', async (req, res) => {
|
||||
try {
|
||||
// Trigger global sync (async - don't wait for completion)
|
||||
syncService.syncAll().catch(console.error);
|
||||
res.json({ success: true, message: 'Global sync started' });
|
||||
} catch (err) {
|
||||
console.error('Error starting global sync:', err);
|
||||
res.status(500).json({ error: 'Failed to start global sync' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { getDb } = require('../db/sqlite');
|
||||
const { sources } = require('../db'); // For source config
|
||||
const { sources, settings } = require('../db'); // For source config and settings
|
||||
const xtreamApi = require('./xtreamApi');
|
||||
const m3uParser = require('./m3uParser');
|
||||
const epgParser = require('./epgParser');
|
||||
@@ -8,6 +8,74 @@ const epgParser = require('./epgParser');
|
||||
const activeSyncs = new Set(); // sourceId
|
||||
|
||||
class SyncService {
|
||||
constructor() {
|
||||
this.lastSyncTime = null; // Track when global sync last completed
|
||||
this._syncTimer = null; // Server-side sync timer
|
||||
this._currentInterval = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get when the last global sync completed
|
||||
*/
|
||||
getLastSyncTime() {
|
||||
return this.lastSyncTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server-side sync timer based on settings
|
||||
* Should be called once on server startup after initial sync
|
||||
*/
|
||||
async startSyncTimer() {
|
||||
// Get interval from settings
|
||||
const currentSettings = await settings.get();
|
||||
const intervalHours = parseInt(currentSettings.epgRefreshInterval) || 24;
|
||||
|
||||
// If interval is 0, don't start timer (manual only mode)
|
||||
if (intervalHours <= 0) {
|
||||
console.log('[Sync] Auto-sync disabled (manual only mode)');
|
||||
this.stopSyncTimer();
|
||||
this._currentInterval = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const intervalMs = intervalHours * 60 * 60 * 1000;
|
||||
|
||||
// Don't restart if interval hasn't changed
|
||||
if (this._currentInterval === intervalHours && this._syncTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing timer
|
||||
this.stopSyncTimer();
|
||||
|
||||
console.log(`[Sync] Starting server-side sync timer: every ${intervalHours} hours`);
|
||||
|
||||
this._syncTimer = setInterval(async () => {
|
||||
console.log('[Sync] Scheduled sync triggered');
|
||||
await this.syncAll();
|
||||
}, intervalMs);
|
||||
|
||||
this._currentInterval = intervalHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the server-side sync timer
|
||||
*/
|
||||
stopSyncTimer() {
|
||||
if (this._syncTimer) {
|
||||
clearInterval(this._syncTimer);
|
||||
this._syncTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the sync timer with updated settings
|
||||
* Called when sync interval setting changes
|
||||
*/
|
||||
async restartSyncTimer() {
|
||||
await this.startSyncTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync all enabled sources
|
||||
*/
|
||||
@@ -21,7 +89,8 @@ class SyncService {
|
||||
await this.syncSource(source.id);
|
||||
}
|
||||
}
|
||||
console.log('[Sync] Global sync completed');
|
||||
this.lastSyncTime = new Date();
|
||||
console.log('[Sync] Global sync completed at', this.lastSyncTime.toISOString());
|
||||
} catch (err) {
|
||||
console.error('[Sync] Global sync failed:', err);
|
||||
}
|
||||
@@ -164,9 +233,11 @@ class SyncService {
|
||||
}
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 500;
|
||||
// Reduced batch size for better event loop interleaving
|
||||
const BATCH_SIZE = 100;
|
||||
for (let i = 0; i < categories.length; i += BATCH_SIZE) {
|
||||
insertBatch(categories.slice(i, i + BATCH_SIZE));
|
||||
// Yield to event loop between batches to allow other requests
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
|
||||
@@ -244,9 +315,11 @@ class SyncService {
|
||||
}
|
||||
});
|
||||
|
||||
const BATCH_SIZE = 500;
|
||||
// Reduced batch size for better event loop interleaving
|
||||
const BATCH_SIZE = 100;
|
||||
for (let i = 0; i < items.length; i += BATCH_SIZE) {
|
||||
insertBatch(items.slice(i, i + BATCH_SIZE));
|
||||
// Yield to event loop between batches to allow other requests
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user