Add volume, playbackRate, and currentTime props
Introduces new props (volume, playbackRate, currentTime) to VideoPlayer and VideoElement components, allowing external control of volume, playback speed, and initial playback position. Also adds related event handlers (onRateChange, onFullscreenChange, onPictureInPictureChange, onProgress, onDurationChange, onWaiting, onCanPlay) and updates documentation and types accordingly.
This commit is contained in:
@@ -16,6 +16,9 @@ interface VideoElementProps {
|
||||
autoplay?: boolean
|
||||
loop?: boolean
|
||||
muted?: boolean
|
||||
volume?: number
|
||||
playbackRate?: number
|
||||
currentTime?: number
|
||||
subtitles?: SubtitleTrack[]
|
||||
onPlay?: () => void
|
||||
onPause?: () => void
|
||||
@@ -26,6 +29,13 @@ interface VideoElementProps {
|
||||
onLoadedMetadata?: () => void
|
||||
onSeeking?: () => void
|
||||
onSeeked?: () => void
|
||||
onProgress?: (buffered: number) => void
|
||||
onDurationChange?: (duration: number) => void
|
||||
onRateChange?: (playbackRate: number) => void
|
||||
onFullscreenChange?: (isFullscreen: boolean) => void
|
||||
onPictureInPictureChange?: (isPictureInPicture: boolean) => void
|
||||
onWaiting?: () => void
|
||||
onCanPlay?: () => void
|
||||
onAudioTracksLoaded?: (tracks: AudioTrack[]) => void
|
||||
onQualityLevelsLoaded?: (qualities: VideoQuality[]) => void
|
||||
onSubtitleTracksLoaded?: (tracks: SubtitleTrack[]) => void
|
||||
@@ -37,6 +47,9 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
autoplay = false,
|
||||
loop = false,
|
||||
muted = false,
|
||||
volume,
|
||||
playbackRate,
|
||||
currentTime: initialCurrentTime,
|
||||
subtitles = [],
|
||||
onPlay,
|
||||
onPause,
|
||||
@@ -47,6 +60,13 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
onLoadedMetadata,
|
||||
onSeeking,
|
||||
onSeeked,
|
||||
onProgress,
|
||||
onDurationChange,
|
||||
onRateChange,
|
||||
onFullscreenChange,
|
||||
onPictureInPictureChange,
|
||||
onWaiting,
|
||||
onCanPlay,
|
||||
onAudioTracksLoaded,
|
||||
onQualityLevelsLoaded,
|
||||
onSubtitleTracksLoaded,
|
||||
@@ -129,7 +149,9 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
duration: video.duration,
|
||||
isLiveBroadcast,
|
||||
}))
|
||||
}, [videoRef, setVideoState])
|
||||
|
||||
onDurationChange?.(video.duration)
|
||||
}, [videoRef, setVideoState, onDurationChange])
|
||||
|
||||
const handleVolumeChange = useCallback(() => {
|
||||
const video = videoRef.current
|
||||
@@ -156,11 +178,29 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
const handleWaiting = useCallback(() => {
|
||||
setVideoState((prev) => ({ ...prev, loading: true }))
|
||||
}, [setVideoState])
|
||||
onWaiting?.()
|
||||
}, [setVideoState, onWaiting])
|
||||
|
||||
const handleCanPlay = useCallback(() => {
|
||||
setVideoState((prev) => ({ ...prev, loading: false }))
|
||||
}, [setVideoState])
|
||||
onCanPlay?.()
|
||||
}, [setVideoState, onCanPlay])
|
||||
|
||||
const handleProgress = useCallback(() => {
|
||||
const video = videoRef.current
|
||||
if (!video) return
|
||||
|
||||
const buffered = video.buffered.length > 0 ? video.buffered.end(video.buffered.length - 1) : 0
|
||||
onProgress?.(buffered)
|
||||
}, [videoRef, onProgress])
|
||||
|
||||
const handleRateChange = useCallback(() => {
|
||||
const video = videoRef.current
|
||||
if (!video) return
|
||||
|
||||
setVideoState((prev) => ({ ...prev, playbackRate: video.playbackRate }))
|
||||
onRateChange?.(video.playbackRate)
|
||||
}, [videoRef, setVideoState, onRateChange])
|
||||
|
||||
const handleEnded = useCallback(() => {
|
||||
setVideoState((prev) => ({ ...prev, playing: false }))
|
||||
@@ -212,19 +252,21 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
const handleFullscreenChange = () => {
|
||||
const isFullscreen = !!document.fullscreenElement
|
||||
setVideoState((prev) => ({ ...prev, fullscreen: isFullscreen }))
|
||||
onFullscreenChange?.(isFullscreen)
|
||||
}
|
||||
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||||
return () => {
|
||||
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
||||
}
|
||||
}, [setVideoState])
|
||||
}, [setVideoState, onFullscreenChange])
|
||||
|
||||
// Handle PIP changes
|
||||
useEffect(() => {
|
||||
const handlePIPChange = () => {
|
||||
const isPIP = !!document.pictureInPictureElement
|
||||
setVideoState((prev) => ({ ...prev, pictureInPicture: isPIP }))
|
||||
onPictureInPictureChange?.(isPIP)
|
||||
}
|
||||
|
||||
document.addEventListener('enterpictureinpicture', handlePIPChange)
|
||||
@@ -234,7 +276,40 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
document.removeEventListener('enterpictureinpicture', handlePIPChange)
|
||||
document.removeEventListener('leavepictureinpicture', handlePIPChange)
|
||||
}
|
||||
}, [setVideoState])
|
||||
}, [setVideoState, onPictureInPictureChange])
|
||||
|
||||
// Apply volume prop to video element
|
||||
useEffect(() => {
|
||||
const video = videoRef.current
|
||||
if (!video || volume === undefined) return
|
||||
|
||||
// Clamp volume between 0 and 1
|
||||
const clampedVolume = Math.max(0, Math.min(1, volume))
|
||||
if (video.volume !== clampedVolume) {
|
||||
video.volume = clampedVolume
|
||||
}
|
||||
}, [volume, videoRef])
|
||||
|
||||
// Apply playbackRate prop to video element
|
||||
useEffect(() => {
|
||||
const video = videoRef.current
|
||||
if (!video || playbackRate === undefined) return
|
||||
|
||||
if (video.playbackRate !== playbackRate) {
|
||||
video.playbackRate = playbackRate
|
||||
}
|
||||
}, [playbackRate, videoRef])
|
||||
|
||||
// Apply currentTime prop to video element (only once on mount or when it changes)
|
||||
useEffect(() => {
|
||||
const video = videoRef.current
|
||||
if (!video || initialCurrentTime === undefined) return
|
||||
|
||||
// Only seek if the difference is significant (more than 1 second)
|
||||
if (Math.abs(video.currentTime - initialCurrentTime) > 1) {
|
||||
video.currentTime = initialCurrentTime
|
||||
}
|
||||
}, [initialCurrentTime, videoRef])
|
||||
|
||||
// Process subtitles - convert SRT to VTT blob URLs and merge with HLS subtitles
|
||||
useEffect(() => {
|
||||
@@ -747,6 +822,8 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
onSeeked={handleSeeked}
|
||||
onWaiting={handleWaiting}
|
||||
onCanPlay={handleCanPlay}
|
||||
onProgress={handleProgress}
|
||||
onRateChange={handleRateChange}
|
||||
onEnded={handleEnded}
|
||||
onError={handleError}
|
||||
onClick={handleVideoClick}
|
||||
|
||||
Reference in New Issue
Block a user