forked from Github/frigate
Motion review timeline (#10235)
* initial motion and audio timeline with dummy data * initial motion and audio timeline with dummy data
This commit is contained in:
209
web/src/hooks/use-event-segment-utils.ts
Normal file
209
web/src/hooks/use-event-segment-utils.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { ReviewSegment } from "@/types/review";
|
||||
|
||||
export const useEventSegmentUtils = (
|
||||
segmentDuration: number,
|
||||
events: ReviewSegment[],
|
||||
severityType: string,
|
||||
) => {
|
||||
const getSegmentStart = useCallback(
|
||||
(time: number): number => {
|
||||
return Math.floor(time / segmentDuration) * segmentDuration;
|
||||
},
|
||||
[segmentDuration],
|
||||
);
|
||||
|
||||
const getSegmentEnd = useCallback(
|
||||
(time: number | undefined): number => {
|
||||
if (time) {
|
||||
return (
|
||||
Math.floor(time / segmentDuration) * segmentDuration + segmentDuration
|
||||
);
|
||||
} else {
|
||||
return Date.now() / 1000 + segmentDuration;
|
||||
}
|
||||
},
|
||||
[segmentDuration],
|
||||
);
|
||||
|
||||
const mapSeverityToNumber = useCallback((severity: string): number => {
|
||||
switch (severity) {
|
||||
case "significant_motion":
|
||||
return 1;
|
||||
case "detection":
|
||||
return 2;
|
||||
case "alert":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const displaySeverityType = useMemo(
|
||||
() => mapSeverityToNumber(severityType ?? ""),
|
||||
[mapSeverityToNumber, severityType],
|
||||
);
|
||||
|
||||
const getSeverity = useCallback(
|
||||
(time: number, displaySeverityType: number): number[] => {
|
||||
const activeEvents = events?.filter((event) => {
|
||||
const segmentStart = getSegmentStart(event.start_time);
|
||||
const segmentEnd = getSegmentEnd(event.end_time);
|
||||
return time >= segmentStart && time < segmentEnd;
|
||||
});
|
||||
|
||||
if (activeEvents?.length === 0) return [0];
|
||||
const severityValues = activeEvents.map((event) =>
|
||||
mapSeverityToNumber(event.severity),
|
||||
);
|
||||
const highestSeverityValue = Math.max(...severityValues);
|
||||
|
||||
if (
|
||||
severityValues.includes(displaySeverityType) &&
|
||||
displaySeverityType !== highestSeverityValue
|
||||
) {
|
||||
return [displaySeverityType, highestSeverityValue];
|
||||
} else {
|
||||
return [highestSeverityValue];
|
||||
}
|
||||
},
|
||||
[events, getSegmentStart, getSegmentEnd, mapSeverityToNumber],
|
||||
);
|
||||
|
||||
const getReviewed = useCallback(
|
||||
(time: number): boolean => {
|
||||
return events.some((event) => {
|
||||
const segmentStart = getSegmentStart(event.start_time);
|
||||
const segmentEnd = getSegmentEnd(event.end_time);
|
||||
return (
|
||||
time >= segmentStart && time < segmentEnd && event.has_been_reviewed
|
||||
);
|
||||
});
|
||||
},
|
||||
[events, getSegmentStart, getSegmentEnd],
|
||||
);
|
||||
|
||||
const shouldShowRoundedCorners = useCallback(
|
||||
(
|
||||
segmentTime: number,
|
||||
): {
|
||||
roundTopPrimary: boolean;
|
||||
roundBottomPrimary: boolean;
|
||||
roundTopSecondary: boolean;
|
||||
roundBottomSecondary: boolean;
|
||||
} => {
|
||||
const prevSegmentTime = segmentTime - segmentDuration;
|
||||
const nextSegmentTime = segmentTime + segmentDuration;
|
||||
|
||||
const severityEvents = events.filter((e) => e.severity === severityType);
|
||||
|
||||
const otherEvents = events.filter((e) => e.severity !== severityType);
|
||||
|
||||
const hasPrevSeverityEvent = severityEvents.some((e) => {
|
||||
return (
|
||||
prevSegmentTime >= getSegmentStart(e.start_time) &&
|
||||
prevSegmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
const hasNextSeverityEvent = severityEvents.some((e) => {
|
||||
return (
|
||||
nextSegmentTime >= getSegmentStart(e.start_time) &&
|
||||
nextSegmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
const hasPrevOtherEvent = otherEvents.some((e) => {
|
||||
return (
|
||||
prevSegmentTime >= getSegmentStart(e.start_time) &&
|
||||
prevSegmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
const hasNextOtherEvent = otherEvents.some((e) => {
|
||||
return (
|
||||
nextSegmentTime >= getSegmentStart(e.start_time) &&
|
||||
nextSegmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
const hasOverlappingSeverityEvent = severityEvents.some((e) => {
|
||||
return (
|
||||
segmentTime >= getSegmentStart(e.start_time) &&
|
||||
segmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
const hasOverlappingOtherEvent = otherEvents.some((e) => {
|
||||
return (
|
||||
segmentTime >= getSegmentStart(e.start_time) &&
|
||||
segmentTime < getSegmentEnd(e.end_time)
|
||||
);
|
||||
});
|
||||
|
||||
let roundTopPrimary = false;
|
||||
let roundBottomPrimary = false;
|
||||
let roundTopSecondary = false;
|
||||
let roundBottomSecondary = false;
|
||||
|
||||
if (hasOverlappingSeverityEvent) {
|
||||
roundBottomPrimary = !hasPrevSeverityEvent;
|
||||
roundTopPrimary = !hasNextSeverityEvent;
|
||||
}
|
||||
|
||||
if (hasOverlappingOtherEvent) {
|
||||
roundBottomSecondary = !hasPrevOtherEvent;
|
||||
roundTopSecondary = !hasNextOtherEvent;
|
||||
}
|
||||
|
||||
return {
|
||||
roundTopPrimary,
|
||||
roundBottomPrimary,
|
||||
roundTopSecondary,
|
||||
roundBottomSecondary,
|
||||
};
|
||||
},
|
||||
[events, getSegmentStart, getSegmentEnd, segmentDuration, severityType],
|
||||
);
|
||||
|
||||
const getEventStart = useCallback(
|
||||
(time: number): number => {
|
||||
const matchingEvent = events.find((event) => {
|
||||
return (
|
||||
time >= getSegmentStart(event.start_time) &&
|
||||
time < getSegmentEnd(event.end_time) &&
|
||||
event.severity == severityType
|
||||
);
|
||||
});
|
||||
|
||||
return matchingEvent?.start_time ?? 0;
|
||||
},
|
||||
[events, getSegmentStart, getSegmentEnd, severityType],
|
||||
);
|
||||
|
||||
const getEventThumbnail = useCallback(
|
||||
(time: number): string => {
|
||||
const matchingEvent = events.find((event) => {
|
||||
return (
|
||||
time >= getSegmentStart(event.start_time) &&
|
||||
time < getSegmentEnd(event.end_time) &&
|
||||
event.severity == severityType
|
||||
);
|
||||
});
|
||||
|
||||
return matchingEvent?.thumb_path ?? "";
|
||||
},
|
||||
[events, getSegmentStart, getSegmentEnd, severityType],
|
||||
);
|
||||
|
||||
return {
|
||||
getSegmentStart,
|
||||
getSegmentEnd,
|
||||
getSeverity,
|
||||
displaySeverityType,
|
||||
getReviewed,
|
||||
shouldShowRoundedCorners,
|
||||
getEventStart,
|
||||
getEventThumbnail,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user