فهرست منبع

Disable the `L` key and `right arrow` key when a video is over (#1159)

* disable L key and right arrow key when video is over

* refactor

* fix firefox bug, fix issues with scrubbing

* show ending screen immediately when progress is 100%, improvements
Bartosz Dryl 3 سال پیش
والد
کامیت
473cb5b317

+ 17 - 12
src/shared/components/VideoPlayer/CustomTimeline.tsx

@@ -23,11 +23,17 @@ type CustomTimelineProps = {
   player?: VideoJsPlayer | null
   isFullScreen?: boolean
   playerState: PlayerState
+  setPlayerState: React.Dispatch<React.SetStateAction<PlayerState>>
 }
 
 const UPDATE_INTERVAL = 30
 
-export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullScreen, playerState }) => {
+export const CustomTimeline: React.FC<CustomTimelineProps> = ({
+  player,
+  isFullScreen,
+  playerState,
+  setPlayerState,
+}) => {
   const playProgressThumbRef = useRef<HTMLButtonElement>(null)
   const playProgressRef = useRef<HTMLDivElement>(null)
   const seekBarRef = useRef<HTMLDivElement>(null)
@@ -47,13 +53,11 @@ export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullSc
       return
     }
     const handler = (event: Event) => {
-      if (event.type === 'seeking') {
-        if (!player.paused()) {
-          setPlayedBefore(true)
-          player.pause()
-        }
+      if (event.type === 'seeking' && isScrubbing && !player.paused()) {
+        setPlayedBefore(true)
+        player.pause()
       }
-      if (event.type === 'seeked') {
+      if (event.type === 'seeked' && !isScrubbing) {
         if (playedBefore) {
           player.play()
           setPlayedBefore(false)
@@ -92,7 +96,9 @@ export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullSc
       setPlayProgressWidth(progressPercentage)
       setPlayProgressThumbWidth(playProgressThumb.clientWidth)
 
-      // set loadProgress
+      if (progressPercentage === 100) {
+        setPlayerState('ended')
+      }
 
       // get all buffered time ranges
       const bufferedTimeRanges = Array.from({ length: buffered.length }).map((_, idx) => ({
@@ -114,7 +120,7 @@ export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullSc
     return () => {
       clearInterval(interval)
     }
-  }, [isScrubbing, player, playerState])
+  }, [isScrubbing, player, playerState, setPlayerState])
 
   const handleMouseAndTouchMove = (e: React.MouseEvent | React.TouchEvent) => {
     const seekBar = seekBarRef.current
@@ -155,7 +161,7 @@ export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullSc
 
     const percentage = clamp(round(mouseOrTouchPosition / seekBarWidth, 4), 0, 100)
     const newTime = percentage * (player?.duration() || 0)
-    player?.currentTime(newTime)
+    player.currentTime(newTime)
     setIsScrubbing(false)
   }
 
@@ -166,10 +172,9 @@ export const CustomTimeline: React.FC<CustomTimelineProps> = ({ player, isFullSc
       onMouseMove={handleMouseAndTouchMove}
       onTouchMove={handleMouseAndTouchMove}
       onMouseLeave={handleJumpToTime}
-      onClick={handleJumpToTime}
       onMouseDown={() => setIsScrubbing(true)}
       onTouchStart={() => setIsScrubbing(true)}
-      onMouseUp={() => setIsScrubbing(false)}
+      onMouseUp={handleJumpToTime}
       onTouchEnd={handleJumpToTime}
     >
       <SeekBar ref={seekBarRef}>

+ 12 - 5
src/shared/components/VideoPlayer/VideoPlayer.tsx

@@ -146,15 +146,15 @@ const VideoPlayerComponent: React.ForwardRefRenderFunction<HTMLVideoElement, Vid
       if (event.type === 'waiting' || event.type === 'seeking') {
         setPlayerState('loading')
       }
-      if (event.type === 'canplay' || event.type === 'seeked') {
+      if (event.type === 'canplaythrough' || event.type === 'seeked') {
         if (playerState !== null) {
           setPlayerState('playing')
         }
       }
     }
-    player.on(['waiting', 'canplay', 'seeking', 'seeked'], handler)
+    player.on(['waiting', 'canplaythrough', 'seeking', 'seeked'], handler)
     return () => {
-      player.off(['waiting', 'canplay', 'seeking', 'seeked'], handler)
+      player.off(['waiting', 'canplaythrough', 'seeking', 'seeked'], handler)
     }
   }, [player, playerState])
 
@@ -421,6 +421,8 @@ const VideoPlayerComponent: React.ForwardRefRenderFunction<HTMLVideoElement, Vid
 
   const showBigPlayButton = playerState === null && !isInBackground
   const showPlayerControls = !isInBackground && isLoaded && playerState
+  const showControlsIndicator = !isInBackground || playerState !== 'ended'
+
   return (
     <Container isFullScreen={isFullScreen} className={className} isInBackground={isInBackground}>
       <div data-vjs-player>
@@ -443,7 +445,12 @@ const VideoPlayerComponent: React.ForwardRefRenderFunction<HTMLVideoElement, Vid
         {showPlayerControls && (
           <>
             <ControlsOverlay isFullScreen={isFullScreen}>
-              <CustomTimeline player={player} isFullScreen={isFullScreen} playerState={playerState} />
+              <CustomTimeline
+                player={player}
+                isFullScreen={isFullScreen}
+                playerState={playerState}
+                setPlayerState={setPlayerState}
+              />
               <CustomControls isFullScreen={isFullScreen} isEnded={playerState === 'ended'}>
                 <PlayControl isLoading={playerState === 'loading'}>
                   <PlayButton
@@ -507,7 +514,7 @@ const VideoPlayerComponent: React.ForwardRefRenderFunction<HTMLVideoElement, Vid
             />
           </>
         )}
-        {!isInBackground && <ControlsIndicator player={player} isLoading={playerState === 'loading'} />}
+        {showControlsIndicator && <ControlsIndicator player={player} isLoading={playerState === 'loading'} />}
       </div>
     </Container>
   )

+ 8 - 0
src/shared/components/VideoPlayer/utils.ts

@@ -23,7 +23,9 @@ export const hotkeysHandler = (event: KeyboardEvent, playerInstance: VideoJsPlay
   const currentVolume = Number(playerInstance.volume().toFixed(2))
   const isMuted = playerInstance.muted()
   const isFullscreen = playerInstance.isFullscreen()
+  const duration = playerInstance.duration()
   const isPaused = playerInstance.paused()
+  const isEnded = currentTime === duration
 
   switch (event.code) {
     case 'Space':
@@ -41,6 +43,9 @@ export const hotkeysHandler = (event: KeyboardEvent, playerInstance: VideoJsPlay
       playerInstance.trigger(CustomVideojsEvents.BackwardFiveSec)
       return
     case 'ArrowRight':
+      if (isEnded) {
+        return
+      }
       playerInstance.currentTime(currentTime + 5)
       playerInstance.trigger(CustomVideojsEvents.ForwardFiveSec)
       return
@@ -49,6 +54,9 @@ export const hotkeysHandler = (event: KeyboardEvent, playerInstance: VideoJsPlay
       playerInstance.trigger(CustomVideojsEvents.BackwardTenSec)
       return
     case 'KeyL':
+      if (isEnded) {
+        return
+      }
       playerInstance.currentTime(currentTime + 10)
       playerInstance.trigger(CustomVideojsEvents.ForwardTenSec)
       return