2024-01-20 16:16:14 +00:00
'use client' ;
import { useEffect , useState , forwardRef , useContext , Ref } from 'react' ;
2024-07-10 22:11:18 +00:00
import { IVod } from '@/app/lib/vods' ;
import { useAuth } from '@/app/components/auth' ;
2024-01-20 16:16:14 +00:00
import { getVodTitle } from './vod-page' ;
2024-07-10 22:11:18 +00:00
import { VideoSourceSelector } from '@/app/components/video-source-selector'
import { buildIpfsUrl } from '@/app/lib/ipfs' ;
import { strapiUrl } from '@/app/lib/constants' ;
2024-01-20 16:16:14 +00:00
import MuxPlayer from '@mux/mux-player-react/lazy' ;
import { VideoContext } from './video-context' ;
import MuxPlayerElement from '@mux/mux-player' ;
2024-07-10 22:11:18 +00:00
import type VideoApiElement from "@mux/mux-player" ;
2024-01-20 16:16:14 +00:00
interface IPlayerProps {
vod : IVod ;
setIsPlayerReady : Function ;
}
interface ITokens {
playbackToken : string ;
storyboardToken : string ;
thumbnailToken : string ;
}
async function getMuxPlaybackTokens ( playbackId : string , jwt : string ) : Promise < ITokens > {
const res = await fetch ( ` ${ strapiUrl } /api/mux-asset/secure?id= ${ playbackId } ` , {
headers : {
'Authorization' : ` Bearer ${ jwt } `
}
} )
const json = await res . json ( )
return {
playbackToken : json.playbackToken ,
storyboardToken : json.storyboardToken ,
thumbnailToken : json.thumbnailToken
}
}
function hexToRgba ( hex : string , alpha : number ) {
const r = parseInt ( hex . slice ( 1 , 3 ) , 16 ) ;
const g = parseInt ( hex . slice ( 3 , 5 ) , 16 ) ;
const b = parseInt ( hex . slice ( 5 , 7 ) , 16 ) ;
return ` rgba( ${ r } , ${ g } , ${ b } , ${ alpha } ) ` ;
}
export const VideoPlayer = forwardRef ( function VideoPlayer ( props : IPlayerProps , ref : Ref < MuxPlayerElement > ) : React . JSX . Element {
const { vod , setIsPlayerReady } = props
const title : string = getVodTitle ( vod ) ;
const { authData } = useAuth ( ) ;
const [ selectedVideoSource , setSelectedVideoSource ] = useState ( '' ) ;
const [ isEntitledToCDN , setIsEntitledToCDN ] = useState ( false ) ;
const [ hlsSource , setHlsSource ] = useState < string > ( '' ) ;
const [ isClient , setIsClient ] = useState ( false ) ;
const [ playbackId , setPlaybackId ] = useState ( '' ) ;
const [ src , setSrc ] = useState ( '' ) ;
const [ tokens , setTokens ] = useState ( { } ) ;
const { setTimeStamp } = useContext ( VideoContext ) ;
useEffect ( ( ) = > {
setIsClient ( true ) ;
const token = authData ? . accessToken ;
const playbackId = vod ? . attributes . muxAsset ? . data ? . attributes ? . playbackId ;
if ( token ) setIsEntitledToCDN ( true ) ;
if ( selectedVideoSource === 'Mux' ) {
if ( ! ! token && ! ! playbackId ) {
try {
getMuxPlaybackTokens ( vod . attributes . muxAsset . data . attributes . playbackId , token )
. then ( ( tokens ) = > {
setTokens ( {
playback : tokens.playbackToken ,
storyboard : tokens.storyboardToken ,
thumbnail : tokens.thumbnailToken
} )
setHlsSource ( vod . attributes . muxAsset . data . attributes . playbackId )
setPlaybackId ( vod . attributes . muxAsset . data . attributes . playbackId )
} ) ;
}
catch ( e ) {
console . error ( e )
}
}
} else if ( selectedVideoSource === 'B2' ) {
if ( ! vod . attributes . videoSrcB2 ) return ; // This shouldn't happen because videoSourceSelector won't choose B2 if there is no b2. This return is only for satisfying TS
setHlsSource ( vod . attributes . videoSrcB2 . data . attributes . cdnUrl ) ;
setPlaybackId ( '' ) ;
setSrc ( vod . attributes . videoSrcB2 . data . attributes . cdnUrl ) ;
} else if ( selectedVideoSource === 'IPFSSource' ) {
setHlsSource ( '' ) ;
setPlaybackId ( '' ) ;
setSrc ( buildIpfsUrl ( vod . attributes . videoSrcHash ) )
} else if ( selectedVideoSource === 'IPFS240' ) {
setHlsSource ( '' ) ;
setPlaybackId ( '' ) ;
setSrc ( buildIpfsUrl ( vod . attributes . video240Hash ) )
}
} , [ selectedVideoSource , authData , vod , setHlsSource ] ) ;
if ( ! isClient ) return < > < / >
return (
< >
< MuxPlayer
onCanPlay = { ( ) = > {
setIsPlayerReady ( true ) }
}
ref = { ref }
preload = "auto"
crossOrigin = "*"
loading = "viewport"
playbackId = { playbackId }
src = { src }
tokens = { tokens }
primaryColor = "#FFFFFF"
metadata = { {
video_title : getVodTitle ( vod )
} }
streamType = "on-demand"
onTimeUpdate = { ( evt ) = > {
const muxPlayer = evt . target as VideoApiElement
const { currentTime } = muxPlayer ;
setTimeStamp ( currentTime )
} }
muted
> < / MuxPlayer >
2024-04-08 18:24:54 +00:00
{ / * { v o d ? . a t t r i b u t e s ? . v i d e o S r c B 2 ? . d a t a ? . a t t r i b u t e s ? . c d n U r l & & ( < >
< p className = 'notification' > CDN2 < / p >
< video id = "player" playsinline controls data - poster = "/path/to/poster.jpg" >
< source src = { vod ? . attributes . videoSrcB2 ? . data ? . attributes ? . cdnUrl } type = "video/mp4" / >
< track kind = "captions" label = "English captions" src = "/path/to/captions.vtt" srclang = "en" default / >
< / video >
< / > ) } * / }
2024-01-20 16:16:14 +00:00
< VideoSourceSelector
isMux = { ! ! vod ? . attributes . muxAsset ? . data ? . attributes ? . playbackId }
isB2 = { ! ! vod ? . attributes . videoSrcB2 ? . data ? . attributes ? . cdnUrl }
isIPFSSource = { ! ! vod ? . attributes . videoSrcHash }
isIPFS240 = { ! ! vod ? . attributes . video240Hash }
isEntitledToCDN = { isEntitledToCDN }
selectedVideoSource = { selectedVideoSource }
setSelectedVideoSource = { setSelectedVideoSource }
> < / VideoSourceSelector >
< / >
)
} )