You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
spa_instat_tv/src/features/VideoPlayer/hooks/index.tsx

124 lines
2.8 KiB

import type { ForwardRefRenderFunction, SyntheticEvent } from 'react'
import {
useEffect,
useState,
useRef,
} from 'react'
import isUndefined from 'lodash/isUndefined'
import isNumber from 'lodash/isNumber'
import { useProgressChange } from './useProgressChange'
type Ref = Parameters<ForwardRefRenderFunction<HTMLVideoElement>>[1]
export type Props = {
className?: string,
crossOrigin?: string,
height?: string,
hidden?: boolean,
isFullscreen?: boolean,
muted?: boolean,
onDurationChange?: (durationMs: number) => void,
onEnded?: (e: SyntheticEvent<HTMLVideoElement>) => void,
onError?: (e?: SyntheticEvent<HTMLVideoElement>) => void,
onLoadedProgress?: (loadedMs: number) => void,
onPause?: (e: SyntheticEvent<HTMLVideoElement>) => void,
onPlayedProgress?: (playedMs: number) => void,
onReady?: () => void,
playing?: boolean,
ref?: Ref,
seek?: number | null,
src: string,
volume?: number,
width?: string,
}
const useVideoRef = (ref?: Ref) => {
const videoRef = useRef<HTMLVideoElement>(null)
if (ref && typeof ref === 'object') return ref
return videoRef
}
export const useVideoPlayer = ({
isFullscreen,
onDurationChange,
onError,
onLoadedProgress,
onPlayedProgress,
onReady,
playing,
ref,
seek = null,
src,
volume,
}: Props) => {
const [ready, setReady] = useState(false)
const videoRef = useVideoRef(ref)
const handleReady = () => {
setReady(true)
onReady?.()
}
const handleDurationChange = () => {
onDurationChange?.(videoRef.current?.duration || 0)
}
useEffect(() => {
const video = videoRef.current
if (!video || !src) return
video.src = src
video.load()
}, [src, videoRef])
useEffect(() => {
const video = videoRef.current
if (video && isNumber(seek)) {
video.currentTime = seek
}
}, [seek, videoRef])
useEffect(() => {
const video = videoRef.current
if (!video?.src || !ready || isUndefined(playing)) return
if (playing) {
// автовоспроизведение со звуком иногда может не сработать
// https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#new-behaviors
video.play().catch(onError)
} else {
video.pause()
}
}, [
ready,
playing,
src,
videoRef,
onError,
])
useEffect(() => {
const video = videoRef.current
if (video) {
video.volume = volume ?? 1
}
}, [volume, videoRef])
// Todo this logic is responsible for scrolling to the player, delete if not required
// useEffect(() => {
// videoRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' })
// }, [isFullscreen, videoRef])
return {
handleDurationChange,
handleReady,
videoRef,
...useProgressChange({
onLoadedProgress,
onPlayedProgress,
videoRef,
}),
}
}