Refactored EPG refresh logic

This commit is contained in:
Trevor Mears
2026-01-02 15:00:11 -08:00
parent 02ff6f3f80
commit c48f2e070e
3 changed files with 113 additions and 24 deletions
+11 -4
View File
@@ -3,7 +3,8 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> <meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
@@ -134,12 +135,14 @@
</button> </button>
<button class="video-control-btn" id="btn-mute" title="Mute/Unmute"> <button class="video-control-btn" id="btn-mute" title="Mute/Unmute">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/> <path
d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />
</svg> </svg>
</button> </button>
<button class="video-control-btn" id="btn-pip" title="Picture in Picture"> <button class="video-control-btn" id="btn-pip" title="Picture in Picture">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
<path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"/> <path
d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z" />
</svg> </svg>
</button> </button>
<button class="video-control-btn" id="btn-fullscreen" title="Fullscreen"> <button class="video-control-btn" id="btn-fullscreen" title="Fullscreen">
@@ -322,7 +325,11 @@
<option value="0">Manual only</option> <option value="0">Manual only</option>
</select> </select>
</div> </div>
<p class="hint">Use the 🔄 button next to EPG sources for manual refresh</p> <p class="hint">Use the <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
class="icon" style="width: 1em; height: 1em; vertical-align: middle;">
<path
d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" />
</svg> button next to EPG sources for manual refresh</p>
</div> </div>
</div> </div>
+78 -1
View File
@@ -122,11 +122,83 @@ class EpgGuide {
getRefreshInterval() { getRefreshInterval() {
// Read from server-side player settings (synced via Settings page) // Read from server-side player settings (synced via Settings page)
if (window.app?.player?.settings?.epgRefreshInterval) { if (window.app?.player?.settings?.epgRefreshInterval) {
return parseInt(window.app.player.settings.epgRefreshInterval); return parseFloat(window.app.player.settings.epgRefreshInterval);
} }
return 24; // Default 24 hours return 24; // Default 24 hours
} }
/**
* Start background EPG refresh timer
* Automatically fetches fresh EPG data at the configured interval
*/
startBackgroundRefresh() {
// Clear any existing timer
this.stopBackgroundRefresh();
const intervalHours = this.getRefreshInterval();
// If interval is 0 or invalid, don't start timer (manual refresh only)
if (!intervalHours || intervalHours <= 0) {
console.log('[EPG] Background refresh disabled (manual only mode)');
this._currentRefreshInterval = 0;
return;
}
const intervalMs = intervalHours * 60 * 60 * 1000; // Convert hours to milliseconds
console.log(`[EPG] Starting background refresh timer: every ${intervalHours} hours (${Math.round(intervalMs / 1000)}s)`);
this._backgroundRefreshTimer = setInterval(async () => {
console.log('[EPG] Background refresh triggered');
try {
await this.fetchEpgData(true); // Force refresh
this.lastRefreshTime = new Date();
console.log('[EPG] Background refresh complete');
// Update channel list program info if visible
if (window.app?.channelList) {
window.app.channelList.clearProgramInfoCache();
window.app.channelList.updateVisibleEpgInfo?.();
}
} catch (err) {
console.error('[EPG] Background refresh failed:', err);
}
}, intervalMs);
// Store current interval so we can detect changes
this._currentRefreshInterval = intervalHours;
}
/**
* Stop background EPG refresh timer
*/
stopBackgroundRefresh() {
if (this._backgroundRefreshTimer) {
clearInterval(this._backgroundRefreshTimer);
this._backgroundRefreshTimer = null;
console.log('[EPG] Background refresh timer stopped');
}
}
/**
* Restart background refresh if interval has changed
* Called when settings change
*/
restartBackgroundRefreshIfNeeded() {
const newInterval = this.getRefreshInterval();
if (this._currentRefreshInterval !== newInterval) {
console.log(`[EPG] Refresh interval changed: ${this._currentRefreshInterval}h -> ${newInterval}h`);
this.startBackgroundRefresh();
}
}
/**
* Get last refresh time for display
*/
getLastRefreshTime() {
return this.lastRefreshTime || null;
}
/** /**
* Load EPG data (server-side caching) * Load EPG data (server-side caching)
*/ */
@@ -134,7 +206,12 @@ class EpgGuide {
try { try {
this.container.innerHTML = '<div class="loading"></div>'; this.container.innerHTML = '<div class="loading"></div>';
await this.fetchEpgData(forceRefresh); await this.fetchEpgData(forceRefresh);
this.lastRefreshTime = new Date();
this.render(); this.render();
// Start background refresh timer after initial load
// This ensures EPG data stays fresh while the app is open
this.startBackgroundRefresh();
} catch (err) { } catch (err) {
console.error('Error loading EPG:', err); console.error('Error loading EPG:', err);
this.container.innerHTML = ` this.container.innerHTML = `
+6 -1
View File
@@ -112,10 +112,15 @@ class SettingsPage {
// Load saved value from player settings // Load saved value from player settings
epgRefreshSelect.value = this.app.player.settings.epgRefreshInterval || '24'; epgRefreshSelect.value = this.app.player.settings.epgRefreshInterval || '24';
// Save on change // Save on change and restart background timer
epgRefreshSelect.addEventListener('change', () => { epgRefreshSelect.addEventListener('change', () => {
this.app.player.settings.epgRefreshInterval = epgRefreshSelect.value; this.app.player.settings.epgRefreshInterval = epgRefreshSelect.value;
this.app.player.saveSettings(); this.app.player.saveSettings();
// Restart EPG background refresh with new interval
if (window.app?.epgGuide) {
window.app.epgGuide.restartBackgroundRefreshIfNeeded();
}
}); });
} }