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

158 lines
5.8 KiB
TypeScript
Raw Normal View History

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
{/* {vod?.attributes?.videoSrcB2?.data?.attributes?.cdnUrl && (<>
<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>
</>
)
})