mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-13 00:53:02 +03:00
86 lines
2.4 KiB
TypeScript
86 lines
2.4 KiB
TypeScript
import { Preview } from "@/types/preview";
|
|
import { TimeRange } from "@/types/timeline";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import useSWR from "swr";
|
|
import { useHourRollover } from "@/hooks/use-hour-rollover";
|
|
|
|
type OptionalCameraPreviewProps = {
|
|
camera?: string;
|
|
autoRefresh?: boolean;
|
|
fetchPreviews?: boolean;
|
|
refreshOnHourRollover?: boolean;
|
|
};
|
|
export function useCameraPreviews(
|
|
initialTimeRange: TimeRange,
|
|
{
|
|
camera = "all",
|
|
autoRefresh = true,
|
|
fetchPreviews = true,
|
|
refreshOnHourRollover = false,
|
|
}: OptionalCameraPreviewProps,
|
|
) {
|
|
const [timeRange, setTimeRange] = useState(initialTimeRange);
|
|
|
|
useEffect(() => {
|
|
setTimeRange(initialTimeRange);
|
|
}, [initialTimeRange]);
|
|
|
|
const { data: allPreviews, mutate: refreshPreviews } = useSWR<Preview[]>(
|
|
fetchPreviews
|
|
? `preview/${camera}/start/${Math.round(timeRange.after)}/end/${Math.round(timeRange.before)}`
|
|
: null,
|
|
{ revalidateOnFocus: autoRefresh, revalidateOnReconnect: autoRefresh },
|
|
);
|
|
|
|
// an hour's mp4 is written after that hour ends, so it is never in the
|
|
// response the page loaded with
|
|
useHourRollover(refreshPreviews, refreshOnHourRollover && fetchPreviews);
|
|
|
|
return fetchPreviews ? allPreviews : [];
|
|
}
|
|
|
|
export function getPreviewForTimeRange(
|
|
allPreviews: Preview[],
|
|
camera: string,
|
|
timeRange: TimeRange,
|
|
) {
|
|
let best: Preview | undefined = undefined;
|
|
let bestOverlap = 0;
|
|
|
|
for (const preview of allPreviews) {
|
|
// a preview belongs to the hour it starts in. a camera whose feed drops
|
|
// across the boundary produces one ending minutes into the next hour, and
|
|
// without this it would claim that hour's slot as well.
|
|
if (
|
|
preview.camera != camera ||
|
|
Math.ceil(preview.start) < timeRange.after
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
// the slot for the live hour is stamped at page load and never grows, so
|
|
// an hour-long preview never fits inside it. rank by overlap instead.
|
|
const overlap =
|
|
Math.min(preview.end, timeRange.before) -
|
|
Math.max(preview.start, timeRange.after);
|
|
|
|
if (overlap > bestOverlap) {
|
|
bestOverlap = overlap;
|
|
best = preview;
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
export function usePreviewForTimeRange(
|
|
allPreviews: Preview[],
|
|
camera: string,
|
|
timeRange: TimeRange,
|
|
) {
|
|
return useMemo(
|
|
() => getPreviewForTimeRange(allPreviews, camera, timeRange),
|
|
[allPreviews, camera, timeRange],
|
|
);
|
|
}
|