RTSDA-Website/public/live-status-updater.js
Benjamin Slingo 91a1bb7a54 Restructure project and update gitignore
- Flatten directory structure by moving files from astro-church-website/ to root
- Remove church-core subdirectory in favor of inline Rust library
- Update .gitignore to properly exclude build artifacts, generated files, and dependencies
- Add environment variables, IDE files, and coverage reports to gitignore
- Include generated CSS files and native bindings in ignore patterns
2025-08-30 08:59:27 -04:00

209 lines
6.7 KiB
JavaScript

// 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 = `
<div class="flex items-center space-x-2 bg-red-500 rounded-full px-4 py-2">
<div class="w-3 h-3 bg-white rounded-full animate-ping"></div>
<span class="font-semibold">LIVE NOW</span>
</div>
`;
} else {
heroStatusContainer.innerHTML = `
<div class="flex items-center space-x-2 bg-white/20 rounded-full px-4 py-2">
<div class="w-3 h-3 bg-gray-300 rounded-full"></div>
<span class="font-semibold">OFFLINE</span>
</div>
`;
}
}
// Update video player
if (this.currentlyLive && this.currentStreamUrl) {
// Create/update video element
videoContainer.innerHTML = `
<video
id="live-video-player"
class="w-full h-full"
controls
muted
playsinline
preload="none">
<p class="text-white text-center">Your browser does not support the video tag or HLS streaming.</p>
</video>
`;
// 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 = `
<div class="w-full h-full flex items-center justify-center bg-gray-900 text-white">
<div class="text-center">
<div class="w-16 h-16 mx-auto mb-4 text-gray-400">
<svg fill="currentColor" viewBox="0 0 24 24">
<path d="M21 6.5l-4 4V7c0-0.55-0.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-0.55 0-1 0.45-1 1v10c0 0.55 0.45 1 1 1h12c0.21 0 0.39-0.08 0.54-0.18L19.73 21 21 19.73 3.27 2z"/>
</svg>
</div>
<h3 class="text-2xl font-semibold mb-2">Stream is Offline</h3>
<p class="text-gray-400">We'll be back for our next service</p>
</div>
</div>
`;
}
}
destroy() {
if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
}
this.destroyHLS();
}
}
// Global instance
window.liveStatusUpdater = new LiveStatusUpdater();