Files
frigate/web/src/hooks/use-motion-segment-utils.ts
T

102 lines
2.8 KiB
TypeScript
Raw Normal View History

2024-03-04 16:18:27 -06:00
import { useCallback, useMemo } from "react";
2024-03-05 12:55:44 -07:00
import { MotionData } from "@/types/review";
2024-03-04 10:42:51 -06:00
export const useMotionSegmentUtils = (
segmentDuration: number,
2024-03-05 12:55:44 -07:00
motion_events: MotionData[],
2024-03-04 10:42:51 -06:00
) => {
2024-03-04 16:18:27 -06:00
const halfSegmentDuration = useMemo(
() => segmentDuration / 2,
[segmentDuration],
);
2024-03-04 10:42:51 -06:00
const getSegmentStart = useCallback(
(time: number): number => {
2024-03-04 16:18:27 -06:00
return Math.floor(time / halfSegmentDuration) * halfSegmentDuration;
2024-03-04 10:42:51 -06:00
},
2024-03-04 16:18:27 -06:00
[halfSegmentDuration],
2024-03-04 10:42:51 -06:00
);
const getSegmentEnd = useCallback(
(time: number | undefined): number => {
if (time) {
return (
2024-03-04 16:18:27 -06:00
Math.floor(time / halfSegmentDuration) * halfSegmentDuration +
halfSegmentDuration
2024-03-04 10:42:51 -06:00
);
} else {
2024-03-04 16:18:27 -06:00
return Date.now() / 1000 + halfSegmentDuration;
2024-03-04 10:42:51 -06:00
}
},
2024-03-04 16:18:27 -06:00
[halfSegmentDuration],
2024-03-04 10:42:51 -06:00
);
const interpolateMotionAudioData = useCallback(
2024-03-04 16:18:27 -06:00
(value: number, newMax: number): number => {
return Math.ceil((Math.abs(value) / 100.0) * newMax) || 0;
2024-03-04 10:42:51 -06:00
},
[],
);
const getMotionSegmentValue = useCallback(
(time: number): number => {
2024-03-11 07:56:36 -05:00
const segmentStart = getSegmentStart(time);
const segmentEnd = getSegmentEnd(time);
const matchingEvents = motion_events.filter((event) => {
// Use integer ms math to avoid floating point rounding issues
// when halfSegmentDuration is not an integer
// (eg, 2.5 seconds from timeline zooming)
const eventMs = Math.round(event.start_time * 1000);
const halfMs = Math.round(halfSegmentDuration * 1000);
const eventBucketMs = Math.round(eventMs / halfMs) * halfMs;
const eventRounded = eventBucketMs / 1000;
return eventRounded >= segmentStart && eventRounded < segmentEnd;
2024-03-04 10:42:51 -06:00
});
2024-03-11 07:56:36 -05:00
const totalMotion = matchingEvents.reduce(
(acc, curr) => acc + (curr.motion ?? 0),
0,
);
return totalMotion;
2024-03-04 10:42:51 -06:00
},
[motion_events, getSegmentStart, getSegmentEnd, halfSegmentDuration],
2024-03-04 10:42:51 -06:00
);
const getAudioSegmentValue = useCallback(
(time: number): number => {
const matchingEvent = motion_events.find((event) => {
return (
time >= getSegmentStart(event.start_time) &&
2024-03-04 16:18:27 -06:00
time < getSegmentEnd(event.start_time)
2024-03-04 10:42:51 -06:00
);
});
2024-03-05 12:55:44 -07:00
return matchingEvent?.audio ?? 0;
2024-03-04 10:42:51 -06:00
},
[motion_events, getSegmentStart, getSegmentEnd],
);
const getMotionStart = useCallback(
(time: number): number => {
const matchingEvent = motion_events.find((event) => {
return (
time >= getSegmentStart(event.start_time) &&
time < getSegmentEnd(event.start_time) &&
event.motion
);
});
return matchingEvent?.start_time ?? 0;
},
[motion_events, getSegmentStart, getSegmentEnd],
);
2024-03-04 10:42:51 -06:00
return {
getMotionSegmentValue,
getAudioSegmentValue,
interpolateMotionAudioData,
getMotionStart,
2024-03-04 10:42:51 -06:00
};
};