diff --git a/public/icons.svg b/public/icons.svg index 6a4246f..78796a9 100644 --- a/public/icons.svg +++ b/public/icons.svg @@ -93,5 +93,15 @@ + + + + + + + + + + diff --git a/src/element/live-video-player.tsx b/src/element/live-video-player.tsx index a4dea56..0c1e865 100644 --- a/src/element/live-video-player.tsx +++ b/src/element/live-video-player.tsx @@ -25,8 +25,10 @@ export function LiveVideoPlayer(props: VideoPlayerProps) { const [src, setSrc] = useState(); const [levels, setLevels] = useState>(); const [level, setLevel] = useState(-1); - const [playState, setPlayState] = useState(true); + const [playState, setPlayState] = useState<"loading" | "playing" | "paused">("loading"); const [volume, setVolume] = useState(1); + const [position, setPosition] = useState(); + const [maxPosition, setMaxPosition] = useState(); useEffect(() => { if (streamCached && video.current) { @@ -59,6 +61,7 @@ export function LiveVideoPlayer(props: VideoPlayerProps) { }); hls.on(Hls.Events.LEVEL_SWITCHING, (_, l) => { console.debug("HLS Level Switch", l); + setMaxPosition(l.details?.totalduration); }); // @ts-ignore Can write anyway hlsObj.current = hls; @@ -88,9 +91,12 @@ export function LiveVideoPlayer(props: VideoPlayerProps) { useEffect(() => { if (video.current) { - video.current.onplaying = () => setPlayState(true); - video.current.onpause = () => setPlayState(false); + video.current.onplaying = () => setPlayState("playing"); + video.current.onpause = () => setPlayState("paused"); + video.current.onseeking = () => setPlayState("loading"); + video.current.onplay = () => setPlayState("loading"); video.current.onvolumechange = () => setVolume(video.current?.volume ?? 1); + video.current.ontimeupdate = () => setPosition(video.current?.currentTime); } }, [video]); @@ -110,6 +116,31 @@ export function LiveVideoPlayer(props: VideoPlayerProps) { } } + function seek(e: React.MouseEvent) { + if (e.currentTarget === e.target) { + const bb = (e.target as HTMLDivElement).getBoundingClientRect(); + + const x = e.clientX - bb.x; + const pos = Math.max(0, Math.min(1.0, x / bb.width)); + + if (video.current && maxPosition) { + const ct = maxPosition * pos; + video.current.currentTime = ct; + setPosition(ct); + } + } + } + + function playStateToIcon() { + switch (playState) { + case "playing": + return "pause"; + case "paused": + return "play"; + case "loading": + return "loading"; + } + } return (
{status === VideoStatus.Online && ( @@ -117,19 +148,32 @@ export function LiveVideoPlayer(props: VideoPlayerProps) { className="absolute opacity-0 hover:opacity-100 transition-opacity w-full h-full z-20 bg-[#00000055]" onClick={() => { if (video.current) { - if (playState) { + if (playState === "playing") { video.current.pause(); - } else { + } else if (playState === "paused") { video.current.play(); } } }}>
- +
e.stopPropagation()}> -
+
+ {props.status === StreamState.Ended && playState && maxPosition && position && ( +
+
+
+ )}