"use client"; import { useEffect, useRef, useState } from "react"; import "./MoviePlayer.css"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFastBackward, faFastForward, faPause, faPlay, faVolumeUp, faVolumeMute, faExpand, faDownload, faArrowLeft, faCaretLeft, faAngleLeft, } from "@fortawesome/free-solid-svg-icons"; import { Spinner } from "@/components/Spinner"; import SeekableProgressBar from "./SeekableProgressBar"; export default function MoviePlayer({ videoUrl, title }) { const videoRef = useRef(null); const [isPlaying, setIsPlaying] = useState(false); const [volume, setVolume] = useState(1); const [isMuted, setIsMuted] = useState(false); const [progress, setProgress] = useState(0); const [buffer, setBuffer] = useState(0); // Buffer state const [isFullscreen, setIsFullscreen] = useState(false); const [showControls, setShowControls] = useState(true); const [isBuffering, setIsBuffering] = useState(false); const overlayTimeout = useRef(null); const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }); const playerVersion = "0.0.2 Alpha"; useEffect(() => { const videoElement = videoRef.current; const handlePlay = () => setIsPlaying(true); const handlePause = () => setIsPlaying(false); const handleTimeUpdate = () => { setProgress((videoElement.currentTime / videoElement.duration) * 100); updateBuffer(); // Update buffer on time update }; const handleWaiting = () => setIsBuffering(true); const handlePlaying = () => setIsBuffering(false); const handleProgress = () => updateBuffer(); // Update buffer on progress videoElement.addEventListener("play", handlePlay); videoElement.addEventListener("pause", handlePause); videoElement.addEventListener("timeupdate", handleTimeUpdate); videoElement.addEventListener("waiting", handleWaiting); videoElement.addEventListener("playing", handlePlaying); videoElement.addEventListener("progress", handleProgress); // Listen to progress events return () => { videoElement.removeEventListener("play", handlePlay); videoElement.removeEventListener("pause", handlePause); videoElement.removeEventListener("timeupdate", handleTimeUpdate); videoElement.removeEventListener("waiting", handleWaiting); videoElement.removeEventListener("playing", handlePlaying); videoElement.removeEventListener("progress", handleProgress); // Clean up progress listener }; }, []); useEffect(() => { if (showControls) { if (overlayTimeout.current) { clearTimeout(overlayTimeout.current); } overlayTimeout.current = setTimeout(() => setShowControls(false), 3000); } return () => clearTimeout(overlayTimeout.current); }, [showControls]); const handleContextMenu = (event) => { event.preventDefault(); setContextMenu({ visible: true, x: event.pageX, y: event.pageY, }); }; const hideContextMenu = () => { setContextMenu({ visible: false, x: 0, y: 0 }); }; useEffect(() => { window.addEventListener("click", hideContextMenu); return () => { window.removeEventListener("click", hideContextMenu); }; }, []); const handleFastForward = () => { if (videoRef.current) { videoRef.current.currentTime = Math.min( videoRef.current.duration, videoRef.current.currentTime + 10 ); } }; const handleRewind = () => { if (videoRef.current) { videoRef.current.currentTime = Math.max( 0, videoRef.current.currentTime - 10 ); } }; const togglePlayPause = () => { if (isPlaying) { videoRef.current.pause(); setShowControls(true); } else { videoRef.current.play(); setShowControls(false); } }; const handleVolumeChange = (event) => { const volumeValue = event.target.value; setVolume(volumeValue); videoRef.current.volume = volumeValue; setIsMuted(volumeValue === 0); }; const toggleMute = () => { if (isMuted) { videoRef.current.volume = volume; setIsMuted(false); } else { videoRef.current.volume = 0; setIsMuted(true); } }; const toggleFullscreen = () => { const doc = window.document; const docEl = doc.documentElement; const requestFullscreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullscreen || docEl.msRequestFullscreen; const exitFullscreen = doc.exitFullscreen || doc.mozCancelFullScreen || docEl.webkitExitFullscreen || doc.msExitFullscreen; if (!isFullscreen) { requestFullscreen.call(docEl); } else { exitFullscreen.call(doc); } setIsFullscreen(!isFullscreen); }; const handleSeek = (newProgress) => { videoRef.current.currentTime = (newProgress / 100) * videoRef.current.duration; setProgress(newProgress); }; const handleMouseMove = () => { setShowControls(true); }; const formatTime = (seconds) => { if (isNaN(seconds)) { return '00:00:00'; } const wholeSeconds = Math.floor(seconds); const hours = Math.floor(wholeSeconds / 3600); const minutes = Math.floor((wholeSeconds % 3600) / 60); const secs = wholeSeconds % 60; const formattedHours = String(hours).padStart(2, '0'); const formattedMinutes = String(minutes).padStart(2, '0'); const formattedSeconds = String(secs).padStart(2, '0'); return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`; }; const updateBuffer = () => { const videoElement = videoRef.current; if (videoElement.buffered.length > 0) { const bufferEnd = videoElement.buffered.end(videoElement.buffered.length - 1); const bufferValue = (bufferEnd / videoElement.duration) * 100; setBuffer(bufferValue); } }; return (
); }