"use client"; import React, { useEffect, useRef } from "react"; import { useTime } from "../context/time-context"; import { FaExpand, FaCompress, FaTimes, FaEye } from "react-icons/fa"; type VideoInfo = { filename: string; url: string; isSegmented?: boolean; segmentStart?: number; segmentEnd?: number; segmentDuration?: number; }; type VideoPlayerProps = { videosInfo: VideoInfo[]; onVideosReady?: () => void; }; export const SimpleVideosPlayer = ({ videosInfo, onVideosReady, }: VideoPlayerProps) => { const { currentTime, setCurrentTime, isPlaying, setIsPlaying } = useTime(); const videoRefs = useRef<(HTMLVideoElement | null)[]>([]); const [hiddenVideos, setHiddenVideos] = React.useState([]); const [enlargedVideo, setEnlargedVideo] = React.useState(null); const [showHiddenMenu, setShowHiddenMenu] = React.useState(false); const [videosReady, setVideosReady] = React.useState(false); const firstVisibleIdx = videosInfo.findIndex( (video) => !hiddenVideos.includes(video.filename) ); // Initialize video refs array useEffect(() => { videoRefs.current = videoRefs.current.slice(0, videosInfo.length); }, [videosInfo.length]); // Handle videos ready useEffect(() => { let readyCount = 0; const checkReady = () => { readyCount++; if (readyCount === videosInfo.length && onVideosReady) { setVideosReady(true); onVideosReady(); setIsPlaying(true); } }; videoRefs.current.forEach((video, index) => { if (video) { const info = videosInfo[index]; // Setup segment boundaries if (info.isSegmented) { const handleTimeUpdate = () => { const segmentEnd = info.segmentEnd || video.duration; const segmentStart = info.segmentStart || 0; if (video.currentTime >= segmentEnd - 0.05) { video.currentTime = segmentStart; // Also update the global time to reset to start if (index === firstVisibleIdx) { setCurrentTime(0); } } }; const handleLoadedData = () => { video.currentTime = info.segmentStart || 0; checkReady(); }; video.addEventListener('timeupdate', handleTimeUpdate); video.addEventListener('loadeddata', handleLoadedData); // Store cleanup (video as any)._segmentHandlers = () => { video.removeEventListener('timeupdate', handleTimeUpdate); video.removeEventListener('loadeddata', handleLoadedData); }; } else { // For non-segmented videos, handle end of video const handleEnded = () => { video.currentTime = 0; if (index === firstVisibleIdx) { setCurrentTime(0); } }; video.addEventListener('ended', handleEnded); video.addEventListener('canplaythrough', checkReady, { once: true }); // Store cleanup (video as any)._segmentHandlers = () => { video.removeEventListener('ended', handleEnded); }; } } }); return () => { videoRefs.current.forEach((video) => { if (video && (video as any)._segmentHandlers) { (video as any)._segmentHandlers(); } }); }; }, [videosInfo, onVideosReady, setIsPlaying, firstVisibleIdx, setCurrentTime]); // Handle play/pause useEffect(() => { if (!videosReady) return; videoRefs.current.forEach((video, idx) => { if (video && !hiddenVideos.includes(videosInfo[idx].filename)) { if (isPlaying) { video.play().catch(e => { if (e.name !== 'AbortError') { console.error("Error playing video"); } }); } else { video.pause(); } } }); }, [isPlaying, videosReady, hiddenVideos, videosInfo]); // Sync video times useEffect(() => { if (!videosReady) return; videoRefs.current.forEach((video, index) => { if (video && !hiddenVideos.includes(videosInfo[index].filename)) { const info = videosInfo[index]; let targetTime = currentTime; if (info.isSegmented) { targetTime = (info.segmentStart || 0) + currentTime; } if (Math.abs(video.currentTime - targetTime) > 0.2) { video.currentTime = targetTime; } } }); }, [currentTime, videosInfo, videosReady, hiddenVideos]); // Handle time update from first visible video const handleTimeUpdate = (e: React.SyntheticEvent) => { const video = e.target as HTMLVideoElement; const videoIndex = videoRefs.current.findIndex(ref => ref === video); const info = videosInfo[videoIndex]; if (info) { let globalTime = video.currentTime; if (info.isSegmented) { globalTime = video.currentTime - (info.segmentStart || 0); } setCurrentTime(globalTime); } }; // Handle play click for segmented videos const handlePlay = (video: HTMLVideoElement, info: VideoInfo) => { if (info.isSegmented) { const segmentStart = info.segmentStart || 0; const segmentEnd = info.segmentEnd || video.duration; if (video.currentTime < segmentStart || video.currentTime >= segmentEnd) { video.currentTime = segmentStart; } } video.play(); }; return ( <> {/* Hidden videos menu */} {hiddenVideos.length > 0 && (
{showHiddenMenu && (
Restore hidden videos:
{hiddenVideos.map((filename) => ( ))}
)}
)} {/* Videos */}
{videosInfo.map((info, idx) => { if (hiddenVideos.includes(info.filename)) return null; const isEnlarged = enlargedVideo === info.filename; const isFirstVisible = idx === firstVisibleIdx; return (

{info.filename}

); })}
); }; export default SimpleVideosPlayer;