diff --git a/docker/showerloop/Caddyfile.default.template b/docker/showerloop/Caddyfile.default.template index e371100..50752f3 100644 --- a/docker/showerloop/Caddyfile.default.template +++ b/docker/showerloop/Caddyfile.default.template @@ -49,7 +49,7 @@ X-Frame-Options "SAMEORIGIN" # Update CSP to allow media content, scripts, and blob URLs with hashes - Content-Security-Policy "default-src 'self'; script-src 'self' blob: 'sha256-ahmIukdQI/ax+3q3Lrjh0Nuqv1/WxkBIGp+vaji6n8w=' 'sha256-qXRIcycfl2OwZL/s1bd83TFw2OcgcMsv1efLB/P3oOs=' 'sha256-SBn8uB66KTUeApEMuYlK6vZG0XcFpXLKlsbXswTKang=' 'sha256-/nvt7GhhWJsKGTVATnlAsNH54uy+pwbcjfx9Z9CT/u0=' 'sha256-rEjWap8xDw9tc9ULmaSD7VQycQasVvSd1OUiH9xKMTM=' 'sha256-9YtzahjQAT4luPVKC0lfwKhhBxWtN3zkQm99EHsc1bk=' 'sha256-PdtHVmWDPYQUs6SFGLloIwo3P4rG5A7ACmYWE1W4Gmk=' 'sha256-ALpx63KUUcf6ky/Teq3GLd+LlD+t+TpXN+bv/1++prU=' 'sha256-llDQiboC1dyoUHsUebHmXSwCs/k0znV6kWogS1Govvs=' 'sha256-zhuCqwglnTqPZ3YumUUbXlmgy3fN4NGHmK+wQzsoQic=' 'sha256-aCakwry3g1c1frt10sPVerFht/3JKT8i7ij3Aoxtsqw=' 'sha256-WE9M5TeJ2Xj1O9eh+0bg7XLyucO5+HCMccMznmiyocw=' 'sha256-FcjCj8HX/odDguAR0bldjsSdXOQMOLnCBKvlLHMZPZI=' 'sha256-tz6nsCI6ZDRK9g0tLDGMU5j9DBRx74XOe8xqaag7D3E=' 'sha256-IsinOLsxFzlWG2kdQIgMjg7l2ebbAaMbWWNSComW7EE=' 'sha256-p92qjinn1HJIBQCKu3QBxLsdKRh4NTdjvCax1ifSpw4=' 'sha256-17JNXqVQbWEbcxlPw9O3wCCa8PEFW9lwv6rOxRzkmXI=' 'sha256-uRkRZZ6nSw2qypQ46ShF3X/DRaPwWezfixlC4pkDuwo=' 'sha256-7bYe3kxYZPs9D4vqScBDsNEjqOw+n8pUFwyFObBKIjw=' 'sha256-IQIGMyVnkPj80HHZ8/Z8ZyxRC5ZPSFiGtTKsUdDqqOs='; style-src 'self' 'sha256-BBl1Pb4QBQZyj2HmRgFr/OhuPRYwV0zoE6G+08FM5TM=' 'sha256-DPggA6+WHJsxuaWoYLnB8XoTcBjKTnq+AmEhXZ2wJfw=' 'sha256-VyDqCue31iv/ickZ+WUp5RF3wMLAGo01mUL0VdbSTc8=' 'sha256-0ZDDv9ptap3zxZW4gGFrmDP9Y5osppDLJj0gRhecFN8=' 'sha256-c9m3RGxNzIy6ShTOIsmAgY77OyuTfgYCG3B2secjHc4=' 'sha256-rweYv4ZmpQ37GLZ2aJrWCpv486xCBOtOb6ngN4dBn8s=' 'sha256-dE50whpmj5sYr02WC5zh9QQNj6tVUQz1eTMmzJh6OU8=' 'sha256-3av5Wckr9yfHOVSXT8j0+EhuI9xI0Jld43e2jilZsro='; img-src 'self' data: blob:; media-src 'self' blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; worker-src 'self' blob:" + Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' https: data: blob:; media-src 'self' blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; worker-src 'self' blob:" # Remove Server header -Server diff --git a/docker/showerloop/public/js/video-init-fixed.js b/docker/showerloop/public/js/video-init-fixed.js index b5b1dd3..80bfcf4 100644 --- a/docker/showerloop/public/js/video-init-fixed.js +++ b/docker/showerloop/public/js/video-init-fixed.js @@ -2,7 +2,7 @@ * Enhanced video.js initialization script * * This script handles video initialization across different browsers, - * properly supporting HLS playback with appropriate fallbacks. + * properly supporting HLS playback regardless of MIME types. */ document.addEventListener('DOMContentLoaded', function() { // Initialize video.js on all video elements with the video-js class @@ -15,18 +15,15 @@ document.addEventListener('DOMContentLoaded', function() { // Only initialize if not already initialized if (!videoElement.classList.contains('vjs-has-started')) { try { - // Get all source elements + // Get sources and detect HLS by filename pattern regardless of MIME type const sourceElements = videoElement.querySelectorAll('source'); - let hasHlsSource = false; - let hasOtherSource = false; + let hlsSource = null; - // 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; + const src = source.getAttribute('src'); + // Detect HLS by the .m3u8 extension in URL even if the MIME type is different + if (src && src.includes('.m3u8')) { + hlsSource = src; } }); @@ -38,7 +35,8 @@ document.addEventListener('DOMContentLoaded', function() { vhs: { overrideNative: !videojs.browser.IS_SAFARI, enableLowInitialPlaylist: true, - limitRenditionsByPlayerDimensions: true + limitRenditionsByPlayerDimensions: true, + useBandwidthFromLocalStorage: true }, nativeAudioTracks: videojs.browser.IS_SAFARI, nativeVideoTracks: videojs.browser.IS_SAFARI @@ -46,18 +44,26 @@ document.addEventListener('DOMContentLoaded', function() { 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); + // Force HLS source if detected regardless of MIME type + if (hlsSource) { + console.log('HLS source detected for ' + videoElement.id + ': ' + hlsSource); player.src({ - src: sourceElements[0].src, - type: 'application/x-mpegurl' + src: hlsSource, + type: 'application/x-mpegURL' }); } - // Improve compatibility with varying window sizes - player.on('play', function() { - player.fluid(true); + // Handle errors + player.on('error', function() { + console.error('Video player error:', player.error()); + // Try to recover by forcing MP4 fallback if available + sourceElements.forEach(function(source) { + if (!source.src.includes('.m3u8')) { + player.src(source.src); + player.play(); + return; + } + }); }); } catch (e) { diff --git a/docker/showerloop/public/js/video-init-fixed.min.js b/docker/showerloop/public/js/video-init-fixed.min.js index 062bd58..c6a5611 100644 --- a/docker/showerloop/public/js/video-init-fixed.min.js +++ b/docker/showerloop/public/js/video-init-fixed.min.js @@ -1 +1 @@ -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)}}))}); +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 o=e.querySelectorAll("source");let r=null;o.forEach(function(e){const o=e.getAttribute("src");o&&o.includes(".m3u8")&&(r=o)});const t=videojs(e.id,{fluid:!0,responsive:!0,html5:{vhs:{overrideNative:!videojs.browser.IS_SAFARI,enableLowInitialPlaylist:!0,limitRenditionsByPlayerDimensions:!0,useBandwidthFromLocalStorage:!0},nativeAudioTracks:videojs.browser.IS_SAFARI,nativeVideoTracks:videojs.browser.IS_SAFARI},playbackRates:[.75,1,1.25,1.5,2]});r&&(console.log("HLS source detected for "+e.id+": "+r),t.src({src:r,type:"application/x-mpegURL"})),t.on("error",function(){console.error("Video player error:",t.error()),o.forEach(function(e){if(!e.src.includes(".m3u8"))return t.src(e.src),void t.play()})})}catch(o){console.error("Error initializing video "+e.id+":",o)}}))})); diff --git a/fix-video-types.js b/fix-video-types.js index 177ca28..df9ba93 100755 --- a/fix-video-types.js +++ b/fix-video-types.js @@ -4,8 +4,7 @@ * 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". + * to use the standard video/mp4 fallback type for all browsers. */ const fs = require('fs'); @@ -35,8 +34,9 @@ function updateHlsMimeTypes(filePath) { 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"'); + // Replace all HLS MIME types with video/mp4 which is more widely supported + html = html.replace(/type=["']application\/x-mpegurl["']/gi, 'type="video/mp4"'); + html = html.replace(/type=["']application\/vnd\.apple\.mpegurl["']/gi, 'type="video/mp4"'); // Add the script include for the fixed video initialization if (!html.includes('video-init-fixed.min.js')) {