mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-07 11:45:24 +03:00
* Add support for review grid * Cleanup reloading on focus * Adjust timeline api to include metadata and before * Be more efficient about getting info * Adjust to new data format * Cleanup types * Cleanup text * Transition to history * Cleanup * remove old web implementations * Cleanup
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import { FrigateConfig } from "@/types/frigateConfig";
|
|
import VideoPlayer from "./VideoPlayer";
|
|
import useSWR from "swr";
|
|
import { useCallback, useMemo, useRef } from "react";
|
|
import { useApiHost } from "@/api";
|
|
import Player from "video.js/dist/types/player";
|
|
|
|
type PreviewPlayerProps = {
|
|
camera: string,
|
|
allPreviews: Preview[],
|
|
startTs: number,
|
|
}
|
|
|
|
type Preview = {
|
|
camera: string,
|
|
src: string,
|
|
type: string,
|
|
start: number,
|
|
end: number,
|
|
}
|
|
|
|
export default function PreviewThumbnailPlayer({ camera, allPreviews, startTs }: PreviewPlayerProps) {
|
|
const { data: config } = useSWR('config');
|
|
const playerRef = useRef<Player | null>(null);
|
|
const apiHost = useApiHost();
|
|
|
|
const relevantPreview = useMemo(() => {
|
|
return Object.values(allPreviews || []).find(
|
|
(preview) => preview.camera == camera && preview.start < startTs && preview.end > startTs
|
|
);
|
|
}, [allPreviews, camera, startTs]);
|
|
|
|
const onHover = useCallback((isHovered: Boolean) => {
|
|
if (!relevantPreview || !playerRef.current) {
|
|
return;
|
|
}
|
|
|
|
if (isHovered) {
|
|
playerRef.current.play();
|
|
} else {
|
|
playerRef.current.pause();
|
|
playerRef.current.currentTime(startTs - relevantPreview.start);
|
|
}
|
|
},
|
|
[relevantPreview, startTs]
|
|
);
|
|
|
|
if (!relevantPreview) {
|
|
return (
|
|
<img className={getThumbWidth(camera, config)} src={`${apiHost}api/preview/${camera}/${startTs}/thumbnail.jpg`} />
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={getThumbWidth(camera, config)}
|
|
onMouseEnter={() => onHover(true)}
|
|
onMouseLeave={() => onHover(false)}
|
|
>
|
|
<VideoPlayer
|
|
options={{
|
|
preload: 'auto',
|
|
autoplay: false,
|
|
controls: false,
|
|
muted: true,
|
|
loadingSpinner: false,
|
|
sources: [
|
|
{
|
|
src: `${relevantPreview.src}`,
|
|
type: 'video/mp4',
|
|
},
|
|
],
|
|
}}
|
|
seekOptions={{}}
|
|
onReady={(player) => {
|
|
playerRef.current = player;
|
|
player.playbackRate(8);
|
|
player.currentTime(startTs - relevantPreview.start);
|
|
}}
|
|
onDispose={() => {
|
|
playerRef.current = null;
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function getThumbWidth(camera: string, config: FrigateConfig) {
|
|
const detect = config.cameras[camera].detect;
|
|
if (detect.width / detect.height > 2) {
|
|
return 'w-[320px]';
|
|
}
|
|
|
|
if (detect.width / detect.height < 1.4) {
|
|
return 'w-[200px]';
|
|
}
|
|
|
|
return 'w-[240px]';
|
|
} |