From 35579e79fbfe5c8cd533598090b532fa6446279a Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 2 May 2025 13:02:34 -0500 Subject: [PATCH] Enhance FloatingVideo component with loading and error handling overlays --- frontend/src/components/FloatingVideo.jsx | 111 +++++++++++++++------- 1 file changed, 79 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/FloatingVideo.jsx b/frontend/src/components/FloatingVideo.jsx index cbb5e1a8..46c191eb 100644 --- a/frontend/src/components/FloatingVideo.jsx +++ b/frontend/src/components/FloatingVideo.jsx @@ -1,9 +1,9 @@ // frontend/src/components/FloatingVideo.js -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import Draggable from 'react-draggable'; import useVideoStore from '../store/useVideoStore'; import mpegts from 'mpegts.js'; -import { CloseButton, Flex } from '@mantine/core'; +import { CloseButton, Flex, Loader, Text, Box } from '@mantine/core'; export default function FloatingVideo() { const isVisible = useVideoStore((s) => s.isVisible); @@ -12,14 +12,17 @@ export default function FloatingVideo() { const videoRef = useRef(null); const playerRef = useRef(null); const videoContainerRef = useRef(null); - const isLoadingRef = useRef(false); + // Convert ref to state so we can use it for rendering + const [isLoading, setIsLoading] = useState(false); + const [loadError, setLoadError] = useState(null); // Safely destroy the player to prevent errors const safeDestroyPlayer = () => { try { if (playerRef.current) { - // Set a flag to ignore abort errors - isLoadingRef.current = false; + // Set loading to false when destroying player + setIsLoading(false); + setLoadError(null); // First unload the source to stop any in-progress fetches if (videoRef.current) { @@ -62,6 +65,10 @@ export default function FloatingVideo() { // Check if we have an existing player and clean it up safeDestroyPlayer(); + // Set loading state to true when starting a new stream + setIsLoading(true); + setLoadError(null); + // Debug log to help diagnose stream issues console.log("Attempting to play stream:", streamUrl); @@ -69,7 +76,7 @@ export default function FloatingVideo() { // If the browser supports MSE for live playback, initialize mpegts.js if (mpegts.getFeatureList().mseLivePlayback) { // Set loading flag - isLoadingRef.current = true; + setIsLoading(true); const player = mpegts.createPlayer({ type: 'mpegts', // MPEG-TS format @@ -91,36 +98,21 @@ export default function FloatingVideo() { // Add events to track loading state player.on(mpegts.Events.LOADING_COMPLETE, () => { - isLoadingRef.current = false; + setIsLoading(false); }); player.on(mpegts.Events.METADATA_ARRIVED, () => { - isLoadingRef.current = false; + setIsLoading(false); }); // Add error event handler player.on(mpegts.Events.ERROR, (errorType, errorDetail) => { - isLoadingRef.current = false; + setIsLoading(false); // Filter out aborted errors if (errorType !== 'NetworkError' || !errorDetail?.includes('aborted')) { console.error('Player error:', errorType, errorDetail); - } - - // If it's a format issue, show a helpful message - if (errorDetail?.includes('Unsupported media type')) { - const message = document.createElement('div'); - message.textContent = "Unsupported stream format. Please try a different stream."; - message.style.position = 'absolute'; - message.style.top = '50%'; - message.style.left = '50%'; - message.style.transform = 'translate(-50%, -50%)'; - message.style.color = 'white'; - message.style.textAlign = 'center'; - message.style.width = '100%'; - if (videoRef.current?.parentNode) { - videoRef.current.parentNode.appendChild(message); - } + setLoadError(`Error: ${errorType}${errorDetail ? ` - ${errorDetail}` : ''}`); } }); @@ -128,12 +120,15 @@ export default function FloatingVideo() { // Don't auto-play until we've loaded properly player.on(mpegts.Events.MEDIA_INFO, () => { + setIsLoading(false); try { player.play().catch(e => { console.log("Auto-play prevented:", e); + setLoadError("Auto-play was prevented. Click play to start."); }); } catch (e) { console.log("Error during play:", e); + setLoadError(`Playback error: ${e.message}`); } }); @@ -141,7 +136,8 @@ export default function FloatingVideo() { playerRef.current = player; } } catch (error) { - isLoadingRef.current = false; + setIsLoading(false); + setLoadError(`Initialization error: ${error.message}`); console.error("Error initializing player:", error); } @@ -186,12 +182,63 @@ export default function FloatingVideo() { - {/* The