8 changed files with 156 additions and 12 deletions
@ -0,0 +1,26 @@
@@ -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 @@
@@ -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 @@
@@ -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() { |
||||
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 ( |
||||
<div> |
||||
<p>Movie view here</p> |
||||
<p>{JSON.stringify(mediaPortable, null, 2)}</p> |
||||
<p></p> |
||||
{streamUrl ? ( |
||||
<VideoPlayer source={streamUrl} onProgress={updateProgress} /> |
||||
) : null} |
||||
</div> |
||||
); |
||||
} |
||||
|
Loading…
Reference in new issue