blakeblackshear.frigate/web/src/components/HistoryViewer/HistoryVideo.tsx

120 lines
2.7 KiB
TypeScript
Raw Normal View History

2022-02-27 15:04:12 +01:00
import { h } from 'preact';
2022-06-24 17:52:17 +02:00
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
2022-02-27 15:04:12 +01:00
import { useApiHost } from '../../api';
import { isNullOrUndefined } from '../../utils/objectUtils';
2022-06-02 23:05:56 +02:00
import 'videojs-seek-buttons';
import 'video.js/dist/video-js.css';
import 'videojs-seek-buttons/dist/videojs-seek-buttons.css';
2022-06-24 17:52:17 +02:00
import videojs, { VideoJsPlayer } from 'video.js';
2022-06-02 23:05:56 +02:00
2022-02-27 15:04:12 +01:00
interface OnTimeUpdateEvent {
timestamp: number;
isPlaying: boolean;
}
interface HistoryVideoProps {
2022-03-06 05:16:31 +01:00
id?: string;
2022-02-27 15:04:12 +01:00
isPlaying: boolean;
currentTime: number;
onTimeUpdate?: (event: OnTimeUpdateEvent) => void;
onPause: () => void;
onPlay: () => void;
}
export const HistoryVideo = ({
id,
isPlaying: videoIsPlaying,
currentTime,
onTimeUpdate,
onPause,
onPlay,
}: HistoryVideoProps) => {
const apiHost = useApiHost();
2022-06-24 16:35:56 +02:00
const videoRef = useRef<HTMLVideoElement>(null);
2022-02-27 15:04:12 +01:00
2022-06-24 17:52:17 +02:00
const [video, setVideo] = useState<VideoJsPlayer>();
2022-02-27 15:04:12 +01:00
useEffect(() => {
2022-06-24 17:52:17 +02:00
let video: VideoJsPlayer
if (videoRef.current) {
video = videojs(videoRef.current, {})
setVideo(video)
2022-02-27 15:04:12 +01:00
}
2022-06-24 17:52:17 +02:00
() => video?.dispose()
2022-06-02 23:05:56 +02:00
}, [videoRef]);
2022-02-27 15:04:12 +01:00
useEffect(() => {
2022-06-24 17:52:17 +02:00
if (!video) {
return
}
2022-06-02 23:05:56 +02:00
if (!id) {
2022-06-24 17:52:17 +02:00
video.pause()
return
2022-06-02 23:05:56 +02:00
}
2022-06-24 17:52:17 +02:00
2022-06-02 23:05:56 +02:00
video.src({
2022-08-17 17:28:32 +02:00
src: `${apiHost}/vod/event/${id}/master.m3u8`,
2022-06-02 23:05:56 +02:00
type: 'application/vnd.apple.mpegurl',
});
video.poster(`${apiHost}/api/events/${id}/snapshot.jpg`);
if (videoIsPlaying) {
video.play();
}
2022-06-24 17:52:17 +02:00
}, [video, id]);
2022-02-27 15:04:12 +01:00
useEffect(() => {
const video = videoRef.current;
const videoExists = !isNullOrUndefined(video);
const hasSeeked = currentTime >= 0;
2022-03-06 05:16:31 +01:00
if (video && videoExists && hasSeeked) {
2022-02-27 15:04:12 +01:00
video.currentTime = currentTime;
}
}, [currentTime, videoRef]);
const onTimeUpdateHandler = useCallback(
(event: Event) => {
const target = event.target as HTMLMediaElement;
const timeUpdateEvent = {
isPlaying: videoIsPlaying,
timestamp: target.currentTime,
};
onTimeUpdate && onTimeUpdate(timeUpdateEvent);
},
[videoIsPlaying, onTimeUpdate]
);
2022-06-24 17:52:17 +02:00
useEffect(() => {
if (video && video.readyState() >= 1) {
if (videoIsPlaying) {
video.play()
} else {
video.pause()
}
}
}, [video, videoIsPlaying])
const onLoad = useCallback(() => {
if (video && video.readyState() >= 1 && videoIsPlaying) {
video.play()
}
}, [video, videoIsPlaying])
2022-02-27 15:04:12 +01:00
return (
2022-06-02 23:05:56 +02:00
<div data-vjs-player>
<video
ref={videoRef}
onTimeUpdate={onTimeUpdateHandler}
2022-06-24 17:52:17 +02:00
onLoadedMetadata={onLoad}
2022-06-02 23:05:56 +02:00
onPause={onPause}
onPlay={onPlay}
className="video-js vjs-fluid"
data-setup="{}"
/>
</div>
2022-02-27 15:04:12 +01:00
);
};