diff --git a/frontend/src/components/VideoPlayer.tsx b/frontend/src/components/VideoPlayer.tsx index e8599f9f..63edf527 100644 --- a/frontend/src/components/VideoPlayer.tsx +++ b/frontend/src/components/VideoPlayer.tsx @@ -1,10 +1,21 @@ import updateVideoProgressById from '../api/actions/updateVideoProgressById'; import updateWatchedState from '../api/actions/updateWatchedState'; import { SponsorBlockSegmentType, SponsorBlockType, VideoResponseType } from '../pages/Video'; -import { Dispatch, Fragment, SetStateAction, SyntheticEvent, useState } from 'react'; +import { + Dispatch, + Fragment, + SetStateAction, + SyntheticEvent, + useEffect, + useRef, + useState, +} from 'react'; import formatTime from '../functions/formatTime'; import { useSearchParams } from 'react-router-dom'; import getApiUrl from '../configuration/getApiUrl'; +import { useKeyPress } from '../functions/useKeypressHook'; + +const VIDEO_PLAYBACK_SPEEDS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3]; type VideoTag = SyntheticEvent; @@ -109,10 +120,23 @@ const VideoPlayer = ({ onWatchStateChanged, onVideoEnd, }: VideoPlayerProps) => { + const videoRef = useRef(null); + const [searchParams] = useSearchParams(); const searchParamVideoProgress = searchParams.get('t'); const [skippedSegments, setSkippedSegments] = useState({}); + const [isMuted, setIsMuted] = useState(false); + const [playbackSpeedIndex, setPlaybackSpeedIndex] = useState(3); + const [lastSubtitleTack, setLastSubtitleTack] = useState(0); + + // const questionmarkPressed = useKeyPress('?'); + const mutePressed = useKeyPress('m'); + const fullscreenPressed = useKeyPress('f'); + const subtitlesPressed = useKeyPress('c'); + const increasePlaybackSpeedPressed = useKeyPress('>'); + const decreasePlaybackSpeedPressed = useKeyPress('<'); + const resetPlaybackSpeedPressed = useKeyPress('='); const videoId = video.data.youtube_id; const videoUrl = video.data.media_url; @@ -153,11 +177,95 @@ const VideoPlayer = ({ onVideoEnd?.(); }; + useEffect(() => { + if (mutePressed) { + setIsMuted(!isMuted); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [mutePressed]); + + useEffect(() => { + if (increasePlaybackSpeedPressed) { + const newSpeed = playbackSpeedIndex + 1; + + if (videoRef.current && VIDEO_PLAYBACK_SPEEDS[newSpeed]) { + videoRef.current.playbackRate = VIDEO_PLAYBACK_SPEEDS[newSpeed]; + + setPlaybackSpeedIndex(newSpeed); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [increasePlaybackSpeedPressed]); + + useEffect(() => { + if (decreasePlaybackSpeedPressed) { + const newSpeedIndex = playbackSpeedIndex - 1; + + if (videoRef.current && VIDEO_PLAYBACK_SPEEDS[newSpeedIndex]) { + videoRef.current.playbackRate = VIDEO_PLAYBACK_SPEEDS[newSpeedIndex]; + + setPlaybackSpeedIndex(newSpeedIndex); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [decreasePlaybackSpeedPressed]); + + useEffect(() => { + if (resetPlaybackSpeedPressed) { + const newSpeedIndex = 3; + + if (videoRef.current && VIDEO_PLAYBACK_SPEEDS[newSpeedIndex]) { + videoRef.current.playbackRate = VIDEO_PLAYBACK_SPEEDS[newSpeedIndex]; + + setPlaybackSpeedIndex(newSpeedIndex); + } + } + }, [resetPlaybackSpeedPressed]); + + useEffect(() => { + if (fullscreenPressed) { + if (videoRef.current && videoRef.current.requestFullscreen && !document.fullscreenElement) { + videoRef.current.requestFullscreen(); + } else { + document.exitFullscreen().catch(e => { + console.error(e); + }); + } + } + }, [fullscreenPressed]); + + useEffect(() => { + if (subtitlesPressed) { + if (videoRef.current) { + const tracks = [...videoRef.current.textTracks]; + + if (tracks.length === 0) { + return; + } + + const lastIndex = tracks.findIndex(x => x.mode === 'showing'); + const active = tracks[lastIndex]; + + if (!active && lastSubtitleTack !== 0) { + tracks[lastSubtitleTack - 1].mode = 'showing'; + } else { + if (active) { + active.mode = 'hidden'; + + setLastSubtitleTack(lastIndex + 1); + } + } + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [subtitlesPressed]); + return ( <>