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

145 lines
5.0 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';
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';
2025-01-11 03:10:04 +00:00
import { postgrestLocalUrl } 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;
}
2025-01-11 03:10:04 +00:00
async function getMuxPlaybackTokens(playback_id: string, jwt: string): Promise<ITokens> {
const res = await fetch(`${postgrestLocalUrl}/api/mux-asset/secure?id=${playback_id}`, {
2024-01-20 16:16:14 +00:00
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);
2025-01-11 03:10:04 +00:00
2024-01-20 16:16:14 +00:00
const [selectedVideoSource, setSelectedVideoSource] = useState('');
const [isEntitledToCDN, setIsEntitledToCDN] = useState(false);
const [hlsSource, setHlsSource] = useState<string>('');
const [isClient, setIsClient] = useState(false);
2025-01-11 03:10:04 +00:00
const [playback_id, setplayback_id] = useState('');
2024-01-20 16:16:14 +00:00
const [src, setSrc] = useState('');
const [tokens, setTokens] = useState({});
const { setTimeStamp } = useContext(VideoContext);
useEffect(() => {
setIsClient(true);
2025-01-11 03:10:04 +00:00
const playback_id = vod?.mux_asset?.playback_id;
2024-01-20 16:16:14 +00:00
if (selectedVideoSource === 'Mux') {
2025-01-11 03:10:04 +00:00
if (!!token && !!playback_id) {
2024-01-20 16:16:14 +00:00
try {
2025-01-11 03:10:04 +00:00
getMuxPlaybackTokens(vod.mux_asset.playback_id, token)
2024-01-20 16:16:14 +00:00
.then((tokens) => {
setTokens({
playback: tokens.playbackToken,
storyboard: tokens.storyboardToken,
thumbnail: tokens.thumbnailToken
})
2025-01-11 03:10:04 +00:00
setHlsSource(vod.mux_asset.playback_id)
setplayback_id(vod.mux_asset.playback_id)
2024-01-20 16:16:14 +00:00
});
}
catch (e) {
console.error(e)
}
}
} else if (selectedVideoSource === 'B2') {
2025-01-11 03:10:04 +00:00
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);
2024-01-20 16:16:14 +00:00
}
2024-11-05 19:48:21 +00:00
}, [selectedVideoSource, vod, setHlsSource]);
2024-01-20 16:16:14 +00:00
if (!isClient) return <></>
return (
<>
<MuxPlayer
onCanPlay={() => {
setIsPlayerReady(true)}
}
ref={ref}
preload="auto"
crossOrigin="*"
loading="viewport"
2025-01-11 03:10:04 +00:00
playback_id={playback_id}
2024-01-20 16:16:14 +00:00
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>
2025-01-11 03:10:04 +00:00
{/* {vod?.attributes?.videoSrcB2?.data?.attributes?.cdn_url && (<>
2024-04-08 18:24:54 +00:00
<p className='notification'>CDN2</p>
<video id="player" playsinline controls data-poster="/path/to/poster.jpg">
2025-01-11 03:10:04 +00:00
<source src={vod?.attributes.videoSrcB2?.data?.attributes?.cdn_url} type="video/mp4" />
2024-04-08 18:24:54 +00:00
<track kind="captions" label="English captions" src="/path/to/captions.vtt" srclang="en" default />
</video>
</>)} */}
2025-01-11 03:10:04 +00:00
{/* <VideoSourceSelector
isMux={!!vod?.mux_asset?.playback_id}
isB2={!!vod?.s3_file?.cdn_url}
2024-01-20 16:16:14 +00:00
isEntitledToCDN={isEntitledToCDN}
selectedVideoSource={selectedVideoSource}
setSelectedVideoSource={setSelectedVideoSource}
2025-01-11 03:10:04 +00:00
></VideoSourceSelector> */}
2024-01-20 16:16:14 +00:00
</>
)
})