8 changed files with 156 additions and 12 deletions
@ -0,0 +1,26 @@ |
|||||||
|
import { MWMediaStream, MWPortableMedia } from "providers"; |
||||||
|
import { useRef } from "react"; |
||||||
|
|
||||||
|
export interface VideoPlayerProps { |
||||||
|
source: MWMediaStream; |
||||||
|
onProgress?: (event: ProgressEvent) => void; |
||||||
|
} |
||||||
|
|
||||||
|
export function VideoPlayer(props: VideoPlayerProps) { |
||||||
|
const videoRef = useRef<HTMLVideoElement | null>(null); |
||||||
|
const mustUseHls = props.source.type === "m3u8"; |
||||||
|
|
||||||
|
return ( |
||||||
|
<video |
||||||
|
className="videoElement" |
||||||
|
ref={videoRef} |
||||||
|
onProgress={(e) => |
||||||
|
props.onProgress && props.onProgress(e.nativeEvent as ProgressEvent) |
||||||
|
} |
||||||
|
controls |
||||||
|
autoPlay |
||||||
|
> |
||||||
|
{!mustUseHls ? <source src={props.source.url} type="video/mp4" /> : null} |
||||||
|
</video> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
import { MWMedia, MWPortableMedia } from "providers"; |
||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { useParams } from "react-router"; |
||||||
|
|
||||||
|
export function usePortableMedia(): MWPortableMedia | undefined { |
||||||
|
const { media } = useParams<{ media: string }>(); |
||||||
|
const [mediaObject, setMediaObject] = useState<MWPortableMedia | undefined>( |
||||||
|
undefined |
||||||
|
); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
try { |
||||||
|
setMediaObject(deserializePortableMedia(media)); |
||||||
|
} catch (err) { |
||||||
|
console.error("Failed to deserialize portable media", err); |
||||||
|
setMediaObject(undefined); |
||||||
|
} |
||||||
|
}, [media, setMediaObject]); |
||||||
|
|
||||||
|
return mediaObject; |
||||||
|
} |
||||||
|
|
||||||
|
export function deserializePortableMedia(media: string): MWPortableMedia { |
||||||
|
return JSON.parse(atob(decodeURIComponent(media))); |
||||||
|
} |
||||||
|
|
||||||
|
export function serializePortableMedia(media: MWPortableMedia): string { |
||||||
|
const data = encodeURIComponent(btoa(JSON.stringify(media))); |
||||||
|
return data; |
||||||
|
} |
@ -1,7 +1,34 @@ |
|||||||
|
import { VideoPlayer } from "components/media/VideoPlayer"; |
||||||
|
import { usePortableMedia } from "hooks/usePortableMedia"; |
||||||
|
import { MWPortableMedia, getStream, MWMediaStream } from "providers"; |
||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { useWatchedContext } from "state/watched"; |
||||||
|
|
||||||
export function MovieView() { |
export function MovieView() { |
||||||
|
const mediaPortable: MWPortableMedia | undefined = usePortableMedia(); |
||||||
|
const [streamUrl, setStreamUrl] = useState<MWMediaStream | undefined>(); |
||||||
|
const store = useWatchedContext(); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
(async () => { |
||||||
|
setStreamUrl(mediaPortable && (await getStream(mediaPortable))); |
||||||
|
})(); |
||||||
|
}, [mediaPortable, setStreamUrl]); |
||||||
|
|
||||||
|
function updateProgress(e: Event) { |
||||||
|
if (!mediaPortable) return; |
||||||
|
const el: HTMLVideoElement = e.currentTarget as HTMLVideoElement; |
||||||
|
store.updateProgress(mediaPortable, el.currentTime, el.duration); |
||||||
|
} |
||||||
|
|
||||||
return ( |
return ( |
||||||
<div> |
<div> |
||||||
<p>Movie view here</p> |
<p>Movie view here</p> |
||||||
|
<p>{JSON.stringify(mediaPortable, null, 2)}</p> |
||||||
|
<p></p> |
||||||
|
{streamUrl ? ( |
||||||
|
<VideoPlayer source={streamUrl} onProgress={updateProgress} /> |
||||||
|
) : null} |
||||||
</div> |
</div> |
||||||
); |
); |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue