import React, { useCallback, useEffect, useRef, useState } from 'react' import styles from './VideoPlayer.module.css' type VideoPlayerProps = { src: string } const PlayIcon = () => ( ) const PauseIcon = () => ( ) const MuteIcon = () => ( ) const UnmuteIcon = () => ( ) const FullscreenIcon = () => ( ) const VideoPlayer: React.FC = ({ src }) => { const [isPlaying, setIsPlaying] = useState(false) const [currentTime, setCurrentTime] = useState(0) const [duration, setDuration] = useState(0) const [isMuted, setIsMuted] = useState(false) const [volume, setVolume] = useState(1) const [isDragging, setIsDragging] = useState(false) const [isControlsVisible, setIsControlsVisible] = useState(true) const [hoverTime, setHoverTime] = useState(null) const videoRef = useRef(null) const progressRef = useRef(null) const volumeRef = useRef(null) const controlsTimeoutRef = useRef(null) const [isSmallSize, setIsSmallSize] = useState(false) const containerRef = useRef(null) useEffect(() => { const video = videoRef.current if (!video) return const setVideoData = () => { setDuration(video.duration) setVolume(video.volume) } const setVideoTime = () => { setCurrentTime(video.currentTime) } const handleEnded = () => { setIsPlaying(false) } video.addEventListener('loadedmetadata', setVideoData) video.addEventListener('timeupdate', setVideoTime) video.addEventListener('ended', handleEnded) return () => { video.removeEventListener('loadedmetadata', setVideoData) video.removeEventListener('timeupdate', setVideoTime) video.removeEventListener('ended', handleEnded) } }, [src]) useEffect(() => { return () => { if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current) } }, []) const showControls = useCallback(() => { setIsControlsVisible(true) if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current) controlsTimeoutRef.current = setTimeout(() => setIsControlsVisible(false), 3000) }, []) const togglePlayPause = useCallback(() => { const video = videoRef.current if (video) { if (isPlaying) video.pause() else video.play().catch(error => console.error('Error playing video:', error)) setIsPlaying(!isPlaying) } }, [isPlaying]) const toggleMute = useCallback(() => { const video = videoRef.current if (video) { const newMutedState = !video.muted video.muted = newMutedState setIsMuted(newMutedState) setVolume(newMutedState ? 0 : (video.volume > 0 ? video.volume : 1)) video.volume = newMutedState ? 0 : (video.volume > 0 ? video.volume : 1) } }, []) const toggleFullscreen = useCallback(() => { const video = videoRef.current if (video) { if (document.fullscreenElement) document.exitFullscreen() else video.requestFullscreen() } }, []) const formatTime = (time: number) => { const minutes = Math.floor(time / 60) const seconds = Math.floor(time % 60) return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` } const updateVideoProgress = useCallback((clientX: number) => { const progressBar = progressRef.current const video = videoRef.current if (progressBar && video) { const rect = progressBar.getBoundingClientRect() const pos = (clientX - rect.left) / rect.width const newTime = pos * video.duration if (newTime >= 0 && newTime <= video.duration) { setHoverTime(newTime) if (isDragging) video.currentTime = newTime } } }, [isDragging]) const handleMouseMove = useCallback((e: React.MouseEvent) => { updateVideoProgress(e.clientX) }, [updateVideoProgress]) const handleMouseLeave = useCallback(() => { if (!isDragging) setHoverTime(null) }, [isDragging]) const handleMouseDown = useCallback((e: React.MouseEvent) => { e.preventDefault() setIsDragging(true) updateVideoProgress(e.clientX) }, [updateVideoProgress]) useEffect(() => { const handleGlobalMouseMove = (e: MouseEvent) => { if (isDragging) updateVideoProgress(e.clientX) } const handleGlobalMouseUp = () => { setIsDragging(false) setHoverTime(null) } if (isDragging) { document.addEventListener('mousemove', handleGlobalMouseMove) document.addEventListener('mouseup', handleGlobalMouseUp) } return () => { document.removeEventListener('mousemove', handleGlobalMouseMove) document.removeEventListener('mouseup', handleGlobalMouseUp) } }, [isDragging, updateVideoProgress]) const checkSize = useCallback(() => { if (containerRef.current) setIsSmallSize(containerRef.current.offsetWidth < 400) }, []) useEffect(() => { checkSize() window.addEventListener('resize', checkSize) return () => window.removeEventListener('resize', checkSize) }, [checkSize]) const handleVolumeChange = useCallback((e: React.MouseEvent) => { const volumeBar = volumeRef.current const video = videoRef.current if (volumeBar && video) { const rect = volumeBar.getBoundingClientRect() const newVolume = (e.clientX - rect.left) / rect.width const clampedVolume = Math.max(0, Math.min(1, newVolume)) video.volume = clampedVolume setVolume(clampedVolume) setIsMuted(clampedVolume === 0) } }, []) return (