From e087324c769fdb5e778619a362ad06f5e61119bf Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Mon, 4 Aug 2025 18:38:31 +0000 Subject: [PATCH] Enable video playback on more browsers and fix video loading issues Integrates HLS.js for wider browser support and fixes video playback by using iframe. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 50814a1e-92e4-4968-856f-7bc7eedf5e8f Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/50814a1e-92e4-4968-856f-7bc7eedf5e8f/tKnLVTM --- client/src/components/video-modal.tsx | 111 +++++++++++++++++++++++--- package-lock.json | 7 ++ package.json | 1 + server/bunny.ts | 11 ++- 4 files changed, 113 insertions(+), 17 deletions(-) diff --git a/client/src/components/video-modal.tsx b/client/src/components/video-modal.tsx index 30af466..cd3a0d9 100644 --- a/client/src/components/video-modal.tsx +++ b/client/src/components/video-modal.tsx @@ -3,6 +3,7 @@ import { X } from "lucide-react"; import { type Video } from "@shared/schema"; import { Button } from "@/components/ui/button"; import { apiRequest } from "@/lib/queryClient"; +import Hls from "hls.js"; interface VideoModalProps { video: Video | null; @@ -45,6 +46,7 @@ function formatDate(date: Date | string): string { export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) { const videoRef = useRef(null); + const hlsRef = useRef(null); useEffect(() => { const handleEscape = (e: KeyboardEvent) => { @@ -66,6 +68,82 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) }; }, [isOpen, onClose]); + // Initialize HLS when video is available + useEffect(() => { + if (isOpen && video && videoRef.current) { + const videoElement = videoRef.current; + + // Clean up previous HLS instance + if (hlsRef.current) { + hlsRef.current.destroy(); + hlsRef.current = null; + } + + const videoUrl = video.videoUrl; + console.log('Loading video:', videoUrl); + + // Check if the video URL is HLS (.m3u8) + if (videoUrl.includes('.m3u8')) { + if (Hls.isSupported()) { + // Use HLS.js for browsers that don't support HLS natively + const hls = new Hls({ + debug: true, + enableWorker: false, + lowLatencyMode: true, + backBufferLength: 90 + }); + + hls.loadSource(videoUrl); + hls.attachMedia(videoElement); + + hls.on(Hls.Events.MANIFEST_PARSED, () => { + console.log('HLS manifest loaded successfully'); + }); + + hls.on(Hls.Events.ERROR, (event, data) => { + console.error('HLS error:', data); + if (data.fatal) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + console.log('Network error, trying to recover...'); + hls.startLoad(); + break; + case Hls.ErrorTypes.MEDIA_ERROR: + console.log('Media error, trying to recover...'); + hls.recoverMediaError(); + break; + default: + console.log('Fatal error, destroying HLS instance...'); + hls.destroy(); + break; + } + } + }); + + hlsRef.current = hls; + } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) { + // For Safari that supports HLS natively + videoElement.src = videoUrl; + console.log('Using native HLS support'); + } else { + console.error('HLS is not supported in this browser'); + } + } else { + // For regular MP4 videos + videoElement.src = videoUrl; + console.log('Using native video support for MP4'); + } + } + + // Cleanup when modal closes + return () => { + if (hlsRef.current) { + hlsRef.current.destroy(); + hlsRef.current = null; + } + }; + }, [isOpen, video]); + const handleVideoPlay = async () => { if (video) { try { @@ -102,17 +180,28 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
- + {video.videoUrl.includes('iframe.mediadelivery.net') ? ( +