diff --git a/client/src/components/video-modal.tsx b/client/src/components/video-modal.tsx index 0aa32bd..3eb20df 100644 --- a/client/src/components/video-modal.tsx +++ b/client/src/components/video-modal.tsx @@ -59,6 +59,10 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) const [showShareMenu, setShowShareMenu] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [videoThumbnail, setVideoThumbnail] = useState(null); + const [isPlaying, setIsPlaying] = useState(false); + const [isMuted, setIsMuted] = useState(false); + const [showControls, setShowControls] = useState(true); + const [controlsTimeout, setControlsTimeout] = useState(null); useEffect(() => { const handleEscape = (e: KeyboardEvent) => { @@ -163,12 +167,18 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) console.log('Razlog preklopa: adaptivni algoritem na podlagi omrežne hitrosti'); }); - // Fragment loading stats + // Fragment loading stats - fixed error handling hls.on(Hls.Events.FRAG_LOADED, (event, data) => { - const stats = data.stats; - const loadTime = stats.loading.end - stats.loading.start; - const speed = (stats.total * 8) / loadTime; // bits per ms = kbps - console.log(`Fragment naložen v ${loadTime}ms, hitrost: ${Math.round(speed)} kbps`); + try { + if (data.frag && data.frag.stats) { + const stats = data.frag.stats; + const loadTime = stats.loading.end - stats.loading.start; + const speed = (stats.total * 8) / loadTime; // bits per ms = kbps + console.log(`Fragment naložen v ${loadTime}ms, hitrost: ${Math.round(speed)} kbps`); + } + } catch (error) { + // Ignore stats errors, they don't affect playback + } }); // Buffer monitoring for dynamic adjustment @@ -222,7 +232,7 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) console.log('Using native video support for MP4'); } - // Capture thumbnail when video loads + // Video event listeners videoElement.addEventListener('loadeddata', () => { console.log('Video data loaded, capturing thumbnail'); setTimeout(() => captureVideoThumbnail(), 1000); @@ -232,6 +242,10 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) console.log('Video can play, capturing thumbnail'); captureVideoThumbnail(); }); + + videoElement.addEventListener('play', () => setIsPlaying(true)); + videoElement.addEventListener('pause', () => setIsPlaying(false)); + videoElement.addEventListener('volumechange', () => setIsMuted(videoElement.muted)); } // Cleanup when modal closes @@ -280,6 +294,52 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps) } }; + const togglePlay = () => { + if (videoRef.current) { + if (isPlaying) { + videoRef.current.pause(); + } else { + videoRef.current.play(); + handleVideoPlay(); + } + } + }; + + const toggleMute = () => { + if (videoRef.current) { + videoRef.current.muted = !videoRef.current.muted; + } + }; + + const toggleFullscreen = () => { + if (videoRef.current) { + if (document.fullscreenElement) { + document.exitFullscreen(); + } else { + videoRef.current.requestFullscreen(); + } + } + }; + + const showControlsTemporarily = () => { + setShowControls(true); + if (controlsTimeout) { + clearTimeout(controlsTimeout); + } + const timeout = setTimeout(() => { + setShowControls(false); + }, 3000); + setControlsTimeout(timeout); + }; + + useEffect(() => { + return () => { + if (controlsTimeout) { + clearTimeout(controlsTimeout); + } + }; + }, [controlsTimeout]); + const getShareUrl = () => { if (!video?.id) return window.location.origin; return `${window.location.origin}?video=${video.id}`; @@ -339,15 +399,21 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
-