110 lines
3.5 KiB
JavaScript
110 lines
3.5 KiB
JavaScript
/**
|
|
* Home Page Controller
|
|
*/
|
|
|
|
class LivePage {
|
|
constructor(app) {
|
|
this.app = app;
|
|
this.handleKeydown = this.handleKeydown.bind(this);
|
|
}
|
|
|
|
async init() {
|
|
// Load sources and channels on initial page load
|
|
await this.app.channelList.loadSources();
|
|
await this.app.channelList.loadChannels();
|
|
|
|
// Silently fetch EPG data for sidebar info
|
|
try {
|
|
await this.app.epgGuide.fetchEpgData();
|
|
|
|
// Clear cache so we don't get stale "null" results from initial render
|
|
this.app.channelList.clearProgramInfoCache();
|
|
|
|
// Update program info in existing DOM elements without re-rendering
|
|
this.updateProgramInfo();
|
|
} catch (err) {
|
|
console.warn('Background EPG fetch failed:', err);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update "Now Playing" info in existing channel elements without blocking UI
|
|
*/
|
|
updateProgramInfo() {
|
|
const channelItems = Array.from(document.querySelectorAll('.channel-item'));
|
|
if (channelItems.length === 0) return;
|
|
|
|
// Build a map for O(1) channel lookups
|
|
const channelMap = new Map();
|
|
this.app.channelList.channels.forEach(c => channelMap.set(c.id, c));
|
|
|
|
// Process in small batches to avoid blocking UI
|
|
const BATCH_SIZE = 50;
|
|
let index = 0;
|
|
|
|
const processBatch = () => {
|
|
const end = Math.min(index + BATCH_SIZE, channelItems.length);
|
|
|
|
for (let i = index; i < end; i++) {
|
|
const item = channelItems[i];
|
|
const channelId = item.dataset.channelId;
|
|
const channel = channelMap.get(channelId);
|
|
|
|
if (channel) {
|
|
const programDiv = item.querySelector('.channel-program');
|
|
if (programDiv) {
|
|
const programTitle = this.app.channelList.getProgramInfo(channel);
|
|
programDiv.textContent = programTitle || '';
|
|
}
|
|
}
|
|
}
|
|
|
|
index = end;
|
|
if (index < channelItems.length) {
|
|
// Yield to browser before next batch
|
|
requestAnimationFrame(processBatch);
|
|
}
|
|
};
|
|
|
|
// Start processing
|
|
requestAnimationFrame(processBatch);
|
|
}
|
|
|
|
handleKeydown(e) {
|
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
|
|
|
switch (e.key) {
|
|
case 'ArrowUp':
|
|
// Check if player handles arrows for volume
|
|
if (this.app.player && !this.app.player.settings.arrowKeysChangeChannel) return;
|
|
|
|
e.preventDefault();
|
|
this.app.channelList.selectPrevChannel();
|
|
break;
|
|
case 'ArrowDown':
|
|
// Check if player handles arrows for volume
|
|
if (this.app.player && !this.app.player.settings.arrowKeysChangeChannel) return;
|
|
|
|
e.preventDefault();
|
|
this.app.channelList.selectNextChannel();
|
|
break;
|
|
}
|
|
}
|
|
|
|
async show() {
|
|
document.addEventListener('keydown', this.handleKeydown);
|
|
|
|
// Only reload if channels aren't already loaded
|
|
if (this.app.channelList.channels.length === 0) {
|
|
await this.app.channelList.loadSources();
|
|
await this.app.channelList.loadChannels();
|
|
}
|
|
}
|
|
|
|
hide() {
|
|
document.removeEventListener('keydown', this.handleKeydown);
|
|
}
|
|
}
|
|
|
|
window.LivePage = LivePage;
|