// Shared live status polling functionality class LiveStatusUpdater { constructor() { this.currentlyLive = false; this.currentStreamUrl = ''; this.pollInterval = null; this.apiUrl = 'https://api.rockvilletollandsda.church/api/v1/stream/status'; this.hls = null; } // Initialize for home page live banner initHomePage() { const liveBanner = document.getElementById('live-status-banner'); if (!liveBanner) return; this.currentlyLive = liveBanner.style.display !== 'none'; this.startPolling(() => this.updateHomeBanner(liveBanner)); } // Initialize for live page video player initLivePage() { const videoContainer = document.querySelector('.aspect-video'); if (!videoContainer) return; const hasVideo = videoContainer.querySelector('video') !== null; this.currentlyLive = hasVideo; this.currentStreamUrl = hasVideo ? videoContainer.querySelector('video')?.src || '' : ''; this.startPolling(() => this.updateLivePage(videoContainer)); } startPolling(updateCallback) { // Check immediately on load this.checkStatus(updateCallback); // Then check every 30 seconds this.pollInterval = setInterval(() => { this.checkStatus(updateCallback); }, 30000); } async checkStatus(updateCallback) { try { console.log('Checking live status...'); const response = await fetch(this.apiUrl); const data = await response.json(); console.log('API response:', data); console.log('Current state:', { currentlyLive: this.currentlyLive, currentStreamUrl: this.currentStreamUrl }); // Only update if status changed if (data.is_live !== this.currentlyLive || data.stream_url !== this.currentStreamUrl) { console.log('Status changed! Updating UI...'); this.currentlyLive = data.is_live; this.currentStreamUrl = data.stream_url || ''; updateCallback(data); } else { console.log('No status change detected'); } } catch (error) { console.error('Failed to update live status:', error); } } updateHomeBanner(liveBanner) { if (this.currentlyLive) { liveBanner.style.display = 'block'; } else { liveBanner.style.display = 'none'; } } // Helper method to detect if browser supports native HLS supportsNativeHLS() { const video = document.createElement('video'); return video.canPlayType('application/vnd.apple.mpegurl') !== ''; } // Helper method to clean up existing HLS instance destroyHLS() { if (this.hls) { this.hls.destroy(); this.hls = null; } } // Helper method to setup HLS.js for non-Safari browsers setupHLS(video, streamUrl) { // Clean up any existing HLS instance this.destroyHLS(); if (this.supportsNativeHLS()) { // Safari - use native HLS support video.src = streamUrl; } else if (window.Hls && window.Hls.isSupported()) { // Chrome, Firefox - use HLS.js this.hls = new window.Hls({ enableWorker: true, lowLatencyMode: true, backBufferLength: 90 }); this.hls.loadSource(streamUrl); this.hls.attachMedia(video); this.hls.on(window.Hls.Events.MANIFEST_PARSED, () => { console.log('HLS manifest parsed, starting playback'); video.play().catch(e => console.log('Auto-play prevented:', e)); }); this.hls.on(window.Hls.Events.ERROR, (event, data) => { console.error('HLS error:', event, data); if (data.fatal) { switch (data.type) { case window.Hls.ErrorTypes.NETWORK_ERROR: console.log('Network error, trying to recover...'); this.hls.startLoad(); break; case window.Hls.ErrorTypes.MEDIA_ERROR: console.log('Media error, trying to recover...'); this.hls.recoverMediaError(); break; default: console.log('Fatal error, destroying HLS instance'); this.destroyHLS(); break; } } }); } else { // Fallback for browsers that don't support HLS at all console.warn('HLS not supported in this browser'); video.src = streamUrl; } } updateLivePage(videoContainer) { // Update hero section status indicator const heroStatusContainer = document.getElementById('live-status-hero'); console.log('Hero status container found:', heroStatusContainer); if (heroStatusContainer) { if (this.currentlyLive) { heroStatusContainer.innerHTML = `
LIVE NOW
`; } else { heroStatusContainer.innerHTML = `
OFFLINE
`; } } // Update video player if (this.currentlyLive && this.currentStreamUrl) { // Create/update video element videoContainer.innerHTML = ` `; // Setup HLS for the new video element const video = document.getElementById('live-video-player'); if (video) { this.setupHLS(video, this.currentStreamUrl); } } else { // Clean up HLS when going offline this.destroyHLS(); // Show offline message videoContainer.innerHTML = `

Stream is Offline

We'll be back for our next service

`; } } destroy() { if (this.pollInterval) { clearInterval(this.pollInterval); this.pollInterval = null; } this.destroyHLS(); } } // Global instance window.liveStatusUpdater = new LiveStatusUpdater();