fp/services/next/app/components/video-player.tsx

145 lines
5.0 KiB
TypeScript

'use client';
import { useEffect, useState, forwardRef, useContext, Ref } from 'react';
import { IVod } from '@/app/lib/vods';
import { getVodTitle } from './vod-page';
import { VideoSourceSelector } from '@/app/components/video-source-selector'
import { buildIpfsUrl } from '@/app/lib/ipfs';
import { postgrestLocalUrl } from '@/app/lib/constants';
import MuxPlayer from '@mux/mux-player-react/lazy';
import { VideoContext } from './video-context';
import MuxPlayerElement from '@mux/mux-player';
import type VideoApiElement from "@mux/mux-player";
interface IPlayerProps {
vod: IVod;
setIsPlayerReady: Function;
}
interface ITokens {
playbackToken: string;
storyboardToken: string;
thumbnailToken: string;
}
async function getMuxPlaybackTokens(playback_id: string, jwt: string): Promise<ITokens> {
const res = await fetch(`${postgrestLocalUrl}/api/mux-asset/secure?id=${playback_id}`, {
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 [selectedVideoSource, setSelectedVideoSource] = useState('');
const [isEntitledToCDN, setIsEntitledToCDN] = useState(false);
const [hlsSource, setHlsSource] = useState<string>('');
const [isClient, setIsClient] = useState(false);
const [playback_id, setplayback_id] = useState('');
const [src, setSrc] = useState('');
const [tokens, setTokens] = useState({});
const { setTimeStamp } = useContext(VideoContext);
useEffect(() => {
setIsClient(true);
const playback_id = vod?.mux_asset?.playback_id;
if (selectedVideoSource === 'Mux') {
if (!!token && !!playback_id) {
try {
getMuxPlaybackTokens(vod.mux_asset.playback_id, token)
.then((tokens) => {
setTokens({
playback: tokens.playbackToken,
storyboard: tokens.storyboardToken,
thumbnail: tokens.thumbnailToken
})
setHlsSource(vod.mux_asset.playback_id)
setplayback_id(vod.mux_asset.playback_id)
});
}
catch (e) {
console.error(e)
}
}
} else if (selectedVideoSource === 'B2') {
if (!vod.s3_file) 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.s3_file.cdn_url);
setplayback_id('');
setSrc(vod.s3_file.cdn_url);
}
}, [selectedVideoSource, vod, setHlsSource]);
if (!isClient) return <></>
return (
<>
<MuxPlayer
onCanPlay={() => {
setIsPlayerReady(true)}
}
ref={ref}
preload="auto"
crossOrigin="*"
loading="viewport"
playback_id={playback_id}
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>
{/* {vod?.attributes?.videoSrcB2?.data?.attributes?.cdn_url && (<>
<p className='notification'>CDN2</p>
<video id="player" playsinline controls data-poster="/path/to/poster.jpg">
<source src={vod?.attributes.videoSrcB2?.data?.attributes?.cdn_url} type="video/mp4" />
<track kind="captions" label="English captions" src="/path/to/captions.vtt" srclang="en" default />
</video>
</>)} */}
{/* <VideoSourceSelector
isMux={!!vod?.mux_asset?.playback_id}
isB2={!!vod?.s3_file?.cdn_url}
isEntitledToCDN={isEntitledToCDN}
selectedVideoSource={selectedVideoSource}
setSelectedVideoSource={setSelectedVideoSource}
></VideoSourceSelector> */}
</>
)
})