From 683d0efbeca10d6d088373e18660ad4c07126072 Mon Sep 17 00:00:00 2001 From: Leopere Date: Fri, 7 Mar 2025 19:29:13 -0500 Subject: [PATCH] Fix file structure and video compatibility issues --- docker/showerloop/Caddyfile.default.template | 2 +- docker/showerloop/Dockerfile | 5 + .../showerloop/public/js/video-init-fixed.js | 125 +++++++++--------- .../public/js/video-init-fixed.min.js | 80 +---------- fix-video-types.js | 91 +++++++++++++ 5 files changed, 162 insertions(+), 141 deletions(-) create mode 100755 fix-video-types.js diff --git a/docker/showerloop/Caddyfile.default.template b/docker/showerloop/Caddyfile.default.template index 4b43adb..e371100 100644 --- a/docker/showerloop/Caddyfile.default.template +++ b/docker/showerloop/Caddyfile.default.template @@ -20,7 +20,7 @@ @tsFiles { path *.ts } - header @m3u8Files Content-Type "application/x-mpegURL" + header @m3u8Files Content-Type "application/vnd.apple.mpegurl" header @tsFiles Content-Type "video/MP2T" # Security headers diff --git a/docker/showerloop/Dockerfile b/docker/showerloop/Dockerfile index 82bc133..e2e7642 100644 --- a/docker/showerloop/Dockerfile +++ b/docker/showerloop/Dockerfile @@ -33,6 +33,11 @@ FROM git.nixc.us/colin/container-base:production-nixiusstatic # Copy the built site from the first stage COPY --from=hugo-builder /public /srv +# Ensure images and static files are properly available +COPY public/images /srv/images +COPY public/favicon.* /srv/ +COPY public/static /srv/static + # Copy our enhanced Caddyfile for development COPY Caddyfile.default.template /etc/caddy/Caddyfile.override diff --git a/docker/showerloop/public/js/video-init-fixed.js b/docker/showerloop/public/js/video-init-fixed.js index 08e3e2b..b5b1dd3 100644 --- a/docker/showerloop/public/js/video-init-fixed.js +++ b/docker/showerloop/public/js/video-init-fixed.js @@ -1,68 +1,71 @@ -// Initialize videos when the DOM is fully loaded +/** + * Enhanced video.js initialization script + * + * This script handles video initialization across different browsers, + * properly supporting HLS playback with appropriate fallbacks. + */ document.addEventListener('DOMContentLoaded', function() { - console.log('[VIDEOJS] Initialization starting...'); + // Initialize video.js on all video elements with the video-js class + const videoElements = document.querySelectorAll('video.video-js'); - if (typeof videojs === 'undefined') { - console.error('[VIDEOJS ERROR] VideoJS is not loaded!'); - return; - } - - // Hero video - try { - var heroVideo = videojs('video-hero-1741299175', { - html5: { - vhs: { - overrideNative: true + if (videoElements && videoElements.length > 0) { + console.log('Found ' + videoElements.length + ' video elements to initialize'); + + videoElements.forEach(function(videoElement) { + // Only initialize if not already initialized + if (!videoElement.classList.contains('vjs-has-started')) { + try { + // Get all source elements + const sourceElements = videoElement.querySelectorAll('source'); + let hasHlsSource = false; + let hasOtherSource = false; + + // Check for HLS sources + sourceElements.forEach(function(source) { + const type = source.getAttribute('type'); + if (type === 'application/x-mpegurl' || type === 'application/vnd.apple.mpegurl') { + hasHlsSource = true; + } else { + hasOtherSource = true; + } + }); + + // Initialize with appropriate settings + const player = videojs(videoElement.id, { + fluid: true, + responsive: true, + html5: { + vhs: { + overrideNative: !videojs.browser.IS_SAFARI, + enableLowInitialPlaylist: true, + limitRenditionsByPlayerDimensions: true + }, + nativeAudioTracks: videojs.browser.IS_SAFARI, + nativeVideoTracks: videojs.browser.IS_SAFARI + }, + playbackRates: [0.75, 1, 1.25, 1.5, 2] + }); + + // Add HLS.js for non-Safari browsers + if (hasHlsSource && !videojs.browser.IS_SAFARI) { + console.log('Adding HLS support for ' + videoElement.id); + player.src({ + src: sourceElements[0].src, + type: 'application/x-mpegurl' + }); + } + + // Improve compatibility with varying window sizes + player.on('play', function() { + player.fluid(true); + }); + + } catch (e) { + console.error('Error initializing video ' + videoElement.id + ':', e); } + } else { + console.log('Video ' + videoElement.id + ' already initialized'); } }); - - heroVideo.on('error', function() { - console.error('[VIDEOJS ERROR] Hero video error:', heroVideo.error()); - }); - - console.log('[VIDEOJS] Hero video initialized'); - } catch (e) { - console.error('[VIDEOJS ERROR] Failed to initialize hero video:', e); } - - // Video 2 - try { - var video2 = videojs('video2', { - html5: { - vhs: { - overrideNative: true - } - } - }); - - video2.on('error', function() { - console.error('[VIDEOJS ERROR] Video2 error:', video2.error()); - }); - - console.log('[VIDEOJS] Video2 initialized'); - } catch (e) { - console.error('[VIDEOJS ERROR] Failed to initialize video2:', e); - } - - // Video 3 - try { - var video3 = videojs('video3', { - html5: { - vhs: { - overrideNative: true - } - } - }); - - video3.on('error', function() { - console.error('[VIDEOJS ERROR] Video3 error:', video3.error()); - }); - - console.log('[VIDEOJS] Video3 initialized'); - } catch (e) { - console.error('[VIDEOJS ERROR] Failed to initialize video3:', e); - } - - console.log('[VIDEOJS] Initialization completed'); }); \ No newline at end of file diff --git a/docker/showerloop/public/js/video-init-fixed.min.js b/docker/showerloop/public/js/video-init-fixed.min.js index 00edc63..062bd58 100644 --- a/docker/showerloop/public/js/video-init-fixed.min.js +++ b/docker/showerloop/public/js/video-init-fixed.min.js @@ -1,79 +1 @@ -// Initialize videos when the DOM is fully loaded -document.addEventListener('DOMContentLoaded', function() { - console.log('[VIDEOJS] Initialization starting...'); - - if (typeof videojs === 'undefined') { - console.error('[VIDEOJS ERROR] VideoJS is not loaded!'); - return; - } - - // Helper function to configure and initialize a video player - function initializeVideoPlayer(elementId, options) { - try { - var defaultOptions = { - html5: { - vhs: { - overrideNative: true, - enableLowInitialPlaylist: true, - limitRenditionsByPlayerDimensions: true, - useBandwidthFromLocalStorage: true - }, - nativeAudioTracks: false, - nativeVideoTracks: false - }, - controlBar: { - pictureInPictureToggle: false - }, - playbackRates: [0.75, 1, 1.25, 1.5, 2], - techOrder: ["html5"] - }; - - // Merge options - var mergedOptions = {}; - for (var key in defaultOptions) { - mergedOptions[key] = defaultOptions[key]; - } - for (var key in options || {}) { - mergedOptions[key] = options[key]; - } - - var player = videojs(elementId, mergedOptions); - - // Fix MIME type issues in Chromium - var hlsSource = player.el().querySelector('source[type="application/x-mpegurl"], source[type="application/vnd.apple.mpegurl"]'); - if (hlsSource) { - // Ensure consistent MIME type - hlsSource.type = 'application/x-mpegurl'; - - // Force HLS reload to ensure proper initialization - var currentSrc = hlsSource.src; - setTimeout(function() { - // Only reload if player hasn't started yet - if (!player.hasStarted_) { - player.src({ - src: currentSrc, - type: 'application/x-mpegurl' - }); - } - }, 100); - } - - player.on('error', function() { - console.error('[VIDEOJS ERROR] Player "' + elementId + '" error:', player.error()); - }); - - console.log('[VIDEOJS] Player "' + elementId + '" initialized'); - return player; - } catch (e) { - console.error('[VIDEOJS ERROR] Failed to initialize player "' + elementId + '":', e); - return null; - } - } - - // Initialize all videos - var heroVideo = initializeVideoPlayer('video-hero-1741299175'); - var video2 = initializeVideoPlayer('video2'); - var video3 = initializeVideoPlayer('video3'); - - console.log('[VIDEOJS] Initialization completed'); -}); \ No newline at end of file +document.addEventListener("DOMContentLoaded",function(){const e=document.querySelectorAll("video.video-js");e&&e.length>0&&(console.log("Found "+e.length+" video elements to initialize"),e.forEach(function(e){if(e.classList.contains("vjs-has-started"))console.log("Video "+e.id+" already initialized");else try{const t=e.querySelectorAll("source");let r=!1,o=!1;t.forEach(function(e){const t=e.getAttribute("type");"application/x-mpegurl"!==t&&"application/vnd.apple.mpegurl"!==t?o=!0:r=!0});const i=videojs(e.id,{fluid:!0,responsive:!0,html5:{vhs:{overrideNative:!videojs.browser.IS_SAFARI,enableLowInitialPlaylist:!0,limitRenditionsByPlayerDimensions:!0},nativeAudioTracks:videojs.browser.IS_SAFARI,nativeVideoTracks:videojs.browser.IS_SAFARI},playbackRates:[.75,1,1.25,1.5,2]});r&&!videojs.browser.IS_SAFARI&&(console.log("Adding HLS support for "+e.id),i.src({src:t[0].src,type:"application/x-mpegurl"})),i.on("play",function(){i.fluid(!0)})}catch(t){console.error("Error initializing video "+e.id+":",t)}}))}); diff --git a/fix-video-types.js b/fix-video-types.js new file mode 100755 index 0000000..177ca28 --- /dev/null +++ b/fix-video-types.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +/** + * Video MIME Type Fixer + * + * This script updates the HLS video source MIME types in HTML files + * to use the more widely supported "application/vnd.apple.mpegurl" type + * instead of "application/x-mpegurl". + */ + +const fs = require('fs'); +const path = require('path'); + +// Function to find all HTML files in a directory recursively +function findHtmlFiles(dir, fileList = []) { + const files = fs.readdirSync(dir); + + files.forEach(file => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + findHtmlFiles(filePath, fileList); + } else if (path.extname(file).toLowerCase() === '.html') { + fileList.push(filePath); + } + }); + + return fileList; +} + +// Function to update HLS mime types in an HTML file +function updateHlsMimeTypes(filePath) { + try { + let html = fs.readFileSync(filePath, 'utf8'); + const originalHtml = html; + + // Update mime type for HLS streams + html = html.replace(/type=["']application\/x-mpegurl["']/gi, 'type="application/vnd.apple.mpegurl"'); + + // Add the script include for the fixed video initialization + if (!html.includes('video-init-fixed.min.js')) { + html = html.replace('', ''); + } + + // Only write file if changes were made + if (html !== originalHtml) { + fs.writeFileSync(filePath, html); + console.log(`Updated: ${filePath}`); + return true; + } else { + console.log(`No changes needed: ${filePath}`); + return false; + } + } catch (err) { + console.error(`Error processing file ${filePath}: ${err.message}`); + return false; + } +} + +// Main function +function main() { + if (process.argv.length < 3) { + console.error('Error: Please provide a directory path.'); + process.exit(1); + } + + const directoryPath = process.argv[2]; + + try { + console.log(`\nScanning directory: ${directoryPath}`); + const htmlFiles = findHtmlFiles(directoryPath); + console.log(`Found ${htmlFiles.length} HTML files.`); + + let updatedCount = 0; + + htmlFiles.forEach(filePath => { + if (updateHlsMimeTypes(filePath)) { + updatedCount++; + } + }); + + console.log(`\nUpdated ${updatedCount} of ${htmlFiles.length} HTML files.`); + + } catch (err) { + console.error(`Error: ${err.message}`); + process.exit(1); + } +} + +main(); \ No newline at end of file