|
@@ -20,6 +20,7 @@ import { SvgActionClose, SvgControlsCaptionsOutline, SvgControlsCaptionsSolid }
|
|
import { Avatar } from '@/components/Avatar'
|
|
import { Avatar } from '@/components/Avatar'
|
|
import { absoluteRoutes } from '@/config/routes'
|
|
import { absoluteRoutes } from '@/config/routes'
|
|
import { useMediaMatch } from '@/hooks/useMediaMatch'
|
|
import { useMediaMatch } from '@/hooks/useMediaMatch'
|
|
|
|
+import { useSegmentAnalytics, videoPlaybackParams } from '@/hooks/useSegmentAnalytics'
|
|
import { usePersonalDataStore } from '@/providers/personalData'
|
|
import { usePersonalDataStore } from '@/providers/personalData'
|
|
import { isMobile } from '@/utils/browser'
|
|
import { isMobile } from '@/utils/browser'
|
|
import { ConsoleLogger, SentryLogger } from '@/utils/logs'
|
|
import { ConsoleLogger, SentryLogger } from '@/utils/logs'
|
|
@@ -133,6 +134,12 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
const [isSharingOverlayOpen, setIsSharingOverlayOpen] = useState(false)
|
|
const [isSharingOverlayOpen, setIsSharingOverlayOpen] = useState(false)
|
|
const { height: playerHeight = 0 } = useResizeObserver({ box: 'border-box', ref: playerRef })
|
|
const { height: playerHeight = 0 } = useResizeObserver({ box: 'border-box', ref: playerRef })
|
|
const customControlsRef = useRef<HTMLDivElement>(null)
|
|
const customControlsRef = useRef<HTMLDivElement>(null)
|
|
|
|
+ const {
|
|
|
|
+ trackVideoPlaybackResumed,
|
|
|
|
+ trackVideoPlaybackPaused,
|
|
|
|
+ trackVideoPlaybackStarted,
|
|
|
|
+ trackVideoPlaybackCompleted,
|
|
|
|
+ } = useSegmentAnalytics()
|
|
|
|
|
|
const customControlsOffset =
|
|
const customControlsOffset =
|
|
((customControlsRef.current?.getBoundingClientRect().top || 0) -
|
|
((customControlsRef.current?.getBoundingClientRect().top || 0) -
|
|
@@ -177,6 +184,18 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
)
|
|
)
|
|
}, [availableTextTracks, captionsLanguage, storedLanguageExists])
|
|
}, [availableTextTracks, captionsLanguage, storedLanguageExists])
|
|
|
|
|
|
|
|
+ const videoPlaybackData = useMemo(
|
|
|
|
+ (): videoPlaybackParams => ({
|
|
|
|
+ videoId: videoId ?? 'no data',
|
|
|
|
+ channelId: video?.channel.id ?? 'no data',
|
|
|
|
+ title: video?.title ?? 'no data',
|
|
|
|
+ totalLength: video?.duration ?? -1,
|
|
|
|
+ fullScreen: isFullScreen,
|
|
|
|
+ quality: video?.mediaMetadata?.pixelHeight?.toString() ?? '1',
|
|
|
|
+ }),
|
|
|
|
+ [videoId, video?.channel.id, video?.title, video?.duration, isFullScreen, video?.mediaMetadata?.pixelHeight]
|
|
|
|
+ )
|
|
|
|
+
|
|
const playVideo = useCallback(
|
|
const playVideo = useCallback(
|
|
async (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
|
|
async (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
|
|
if (!player) {
|
|
if (!player) {
|
|
@@ -186,6 +205,9 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
try {
|
|
try {
|
|
setNeedsManualPlay(false)
|
|
setNeedsManualPlay(false)
|
|
const playPromise = await player.play()
|
|
const playPromise = await player.play()
|
|
|
|
+ if (playPromise) {
|
|
|
|
+ trackVideoPlaybackResumed(videoPlaybackData)
|
|
|
|
+ }
|
|
if (playPromise && callback) callback()
|
|
if (playPromise && callback) callback()
|
|
} catch (error) {
|
|
} catch (error) {
|
|
if (error.name === 'AbortError') {
|
|
if (error.name === 'AbortError') {
|
|
@@ -204,17 +226,21 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
- [videoId, videoJsConfig.videoUrls]
|
|
|
|
|
|
+ [trackVideoPlaybackResumed, videoId, videoPlaybackData, videoJsConfig.videoUrls]
|
|
)
|
|
)
|
|
|
|
|
|
- const pauseVideo = useCallback((player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
|
|
|
|
- if (!player) {
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- withIndicator && player.trigger(CustomVideojsEvents.PauseControl)
|
|
|
|
- callback?.()
|
|
|
|
- player.pause()
|
|
|
|
- }, [])
|
|
|
|
|
|
+ const pauseVideo = useCallback(
|
|
|
|
+ (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
|
|
|
|
+ if (!player) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ withIndicator && player.trigger(CustomVideojsEvents.PauseControl)
|
|
|
|
+ callback?.()
|
|
|
|
+ player.pause()
|
|
|
|
+ trackVideoPlaybackPaused(videoPlaybackData)
|
|
|
|
+ },
|
|
|
|
+ [trackVideoPlaybackPaused, videoPlaybackData]
|
|
|
|
+ )
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
if (!isVideoPending) {
|
|
if (!isVideoPending) {
|
|
@@ -335,12 +361,13 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
}
|
|
}
|
|
const handler = () => {
|
|
const handler = () => {
|
|
setPlayerState('ended')
|
|
setPlayerState('ended')
|
|
|
|
+ trackVideoPlaybackCompleted(videoPlaybackData)
|
|
}
|
|
}
|
|
player.on('ended', handler)
|
|
player.on('ended', handler)
|
|
return () => {
|
|
return () => {
|
|
player.off('ended', handler)
|
|
player.off('ended', handler)
|
|
}
|
|
}
|
|
- }, [nextVideo, player])
|
|
|
|
|
|
+ }, [nextVideo, player, trackVideoPlaybackCompleted, videoPlaybackData])
|
|
|
|
|
|
// handle loadstart
|
|
// handle loadstart
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
@@ -367,13 +394,14 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
.then(() => {
|
|
.then(() => {
|
|
onAddVideoView?.()
|
|
onAddVideoView?.()
|
|
setIsPlaying(true)
|
|
setIsPlaying(true)
|
|
|
|
+ trackVideoPlaybackStarted(videoPlaybackData)
|
|
})
|
|
})
|
|
.catch((e) => {
|
|
.catch((e) => {
|
|
setNeedsManualPlay(true)
|
|
setNeedsManualPlay(true)
|
|
ConsoleLogger.warn('Video autoplay failed', e)
|
|
ConsoleLogger.warn('Video autoplay failed', e)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
- }, [player, isLoaded, autoplay, onAddVideoView])
|
|
|
|
|
|
+ }, [player, isLoaded, autoplay, onAddVideoView, trackVideoPlaybackStarted, videoPlaybackData])
|
|
|
|
|
|
// handle playing and pausing from outside the component
|
|
// handle playing and pausing from outside the component
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
@@ -382,10 +410,12 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
|
|
}
|
|
}
|
|
if (playing) {
|
|
if (playing) {
|
|
playVideo(player)
|
|
playVideo(player)
|
|
|
|
+ trackVideoPlaybackResumed(videoPlaybackData)
|
|
} else {
|
|
} else {
|
|
player.pause()
|
|
player.pause()
|
|
|
|
+ trackVideoPlaybackPaused(videoPlaybackData)
|
|
}
|
|
}
|
|
- }, [playVideo, player, playing])
|
|
|
|
|
|
+ }, [playVideo, player, playing, trackVideoPlaybackPaused, trackVideoPlaybackResumed, videoPlaybackData])
|
|
|
|
|
|
// handle playing and pausing
|
|
// handle playing and pausing
|
|
useEffect(() => {
|
|
useEffect(() => {
|