mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-07-16 13:47:07 +02:00
* implement summary timeline * implement summary timeline * merge dev * conditionally attach listeners only when dragging * set up listeners with a ref
211 lines
6.0 KiB
TypeScript
211 lines
6.0 KiB
TypeScript
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)) {
|
|
const otherSeverityValues = severityValues.filter(
|
|
(severity) => severity !== displaySeverityType,
|
|
);
|
|
const highestOtherSeverityValue = Math.max(...otherSeverityValues);
|
|
return [displaySeverityType, highestOtherSeverityValue];
|
|
} 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,
|
|
};
|
|
};
|