reduce duplicate items and improve time format

This commit is contained in:
Nick Mowen 2023-12-19 06:47:28 -07:00
parent a7f4f9919d
commit 8d143dc655
5 changed files with 101 additions and 80 deletions

View File

@ -47,7 +47,7 @@ export default function HistoryCard({
<LuClock className="h-5 w-5 mr-2 inline" /> <LuClock className="h-5 w-5 mr-2 inline" />
{formatUnixTimestampToDateTime(timeline.time, { {formatUnixTimestampToDateTime(timeline.time, {
strftime_fmt: strftime_fmt:
config.ui.time_format == "24hour" ? "%H:%M:%S" : "%I:%M:%S", config.ui.time_format == "24hour" ? "%H:%M:%S" : "%I:%M:%S %p",
time_style: "medium", time_style: "medium",
date_style: "medium", date_style: "medium",
})} })}

View File

@ -105,7 +105,10 @@ export default function PreviewThumbnailPlayer({
); );
let content; let content;
if (!relevantPreview || !visible) {
if (relevantPreview && !visible) {
content = <div />;
} else if (!relevantPreview) {
if (isCurrentHour(startTs)) { if (isCurrentHour(startTs)) {
content = ( content = (
<img <img

View File

@ -8,6 +8,7 @@ import HistoryCard from "@/components/card/HistoryCard";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import axios from "axios"; import axios from "axios";
import TimelinePlayerCard from "@/components/card/TimelinePlayerCard"; import TimelinePlayerCard from "@/components/card/TimelinePlayerCard";
import { getHourlyTimelineData } from "@/utils/historyUtil";
const API_LIMIT = 120; const API_LIMIT = 120;
@ -59,83 +60,7 @@ function History() {
return []; return [];
} }
const cards: CardsData = {}; return getHourlyTimelineData(timelinePages, detailLevel);
timelinePages.forEach((hourlyTimeline) => {
Object.keys(hourlyTimeline["hours"])
.reverse()
.forEach((hour) => {
const day = new Date(parseInt(hour) * 1000);
day.setHours(0, 0, 0, 0);
const dayKey = (day.getTime() / 1000).toString();
const source_to_types: { [key: string]: string[] } = {};
Object.values(hourlyTimeline["hours"][hour]).forEach((i) => {
const time = new Date(i.timestamp * 1000);
time.setSeconds(0);
time.setMilliseconds(0);
const key = `${i.source_id}-${time.getMinutes()}`;
if (key in source_to_types) {
source_to_types[key].push(i.class_type);
} else {
source_to_types[key] = [i.class_type];
}
});
if (!Object.keys(cards).includes(dayKey)) {
cards[dayKey] = {};
}
cards[dayKey][hour] = {};
Object.values(hourlyTimeline["hours"][hour]).forEach((i) => {
const time = new Date(i.timestamp * 1000);
const key = `${i.camera}-${time.getMinutes()}`;
// detail level for saving items
// detail level determines which timeline items for each moment is returned
// values can be normal, extra, or full
// normal: return all items except active / attribute / gone / stationary / visible unless that is the only item.
// extra: return all items except attribute / gone / visible unless that is the only item
// full: return all items
let add = true;
if (detailLevel == "normal") {
if (
source_to_types[`${i.source_id}-${time.getMinutes()}`].length >
1 &&
[
"active",
"attribute",
"gone",
"stationary",
"visible",
].includes(i.class_type)
) {
add = false;
}
} else if (detailLevel == "extra") {
if (
source_to_types[`${i.source_id}-${time.getMinutes()}`].length >
1 &&
i.class_type in ["attribute", "gone", "visible"]
) {
add = false;
}
}
if (add) {
if (key in cards[dayKey][hour]) {
cards[dayKey][hour][key].entries.push(i);
} else {
cards[dayKey][hour][key] = {
camera: i.camera,
time: time.getTime() / 1000,
entries: [i],
};
}
}
});
});
});
return cards;
}, [detailLevel, timelinePages]); }, [detailLevel, timelinePages]);
const isDone = const isDone =
@ -206,7 +131,10 @@ function History() {
<div key={hour} ref={lastRow ? lastTimelineRef : null}> <div key={hour} ref={lastRow ? lastTimelineRef : null}>
<Heading as="h4"> <Heading as="h4">
{formatUnixTimestampToDateTime(parseInt(hour), { {formatUnixTimestampToDateTime(parseInt(hour), {
strftime_fmt: "%I:00", strftime_fmt:
config.ui.time_format == "24hour"
? "%H:00"
: "%I:00 %p",
time_style: "medium", time_style: "medium",
date_style: "medium", date_style: "medium",
})} })}
@ -229,6 +157,7 @@ function History() {
preview.end > startTs preview.end > startTs
); );
} }
return ( return (
<HistoryCard <HistoryCard
key={key} key={key}

View File

@ -10,6 +10,7 @@ type Card = {
camera: string, camera: string,
time: number, time: number,
entries: Timeline[], entries: Timeline[],
uniqueKeys: string[],
} }
type Preview = { type Preview = {

View File

@ -0,0 +1,88 @@
export function getHourlyTimelineData(
timelinePages: HourlyTimeline[],
detailLevel: string
) {
const cards: CardsData = {};
timelinePages.forEach((hourlyTimeline) => {
Object.keys(hourlyTimeline["hours"])
.reverse()
.forEach((hour) => {
const day = new Date(parseInt(hour) * 1000);
day.setHours(0, 0, 0, 0);
const dayKey = (day.getTime() / 1000).toString();
const source_to_types: { [key: string]: string[] } = {};
Object.values(hourlyTimeline["hours"][hour]).forEach((i) => {
const time = new Date(i.timestamp * 1000);
time.setSeconds(0);
time.setMilliseconds(0);
const key = `${i.source_id}-${time.getMinutes()}`;
if (key in source_to_types) {
source_to_types[key].push(i.class_type);
} else {
source_to_types[key] = [i.class_type];
}
});
if (!Object.keys(cards).includes(dayKey)) {
cards[dayKey] = {};
}
cards[dayKey][hour] = {};
Object.values(hourlyTimeline["hours"][hour]).forEach((i) => {
const time = new Date(i.timestamp * 1000);
const minuteKey = `${i.camera}-${time.getMinutes()}`;
const uniqueKey = `${i.source_id}-${i.class_type}`;
// detail level for saving items
// detail level determines which timeline items for each moment is returned
// values can be normal, extra, or full
// normal: return all items except active / attribute / gone / stationary / visible unless that is the only item.
// extra: return all items except attribute / gone / visible unless that is the only item
// full: return all items
let add = true;
if (detailLevel == "normal") {
if (
source_to_types[`${i.source_id}-${time.getMinutes()}`].length >
1 &&
["active", "attribute", "gone", "stationary", "visible"].includes(
i.class_type
)
) {
add = false;
}
} else if (detailLevel == "extra") {
if (
source_to_types[`${i.source_id}-${time.getMinutes()}`].length >
1 &&
i.class_type in ["attribute", "gone", "visible"]
) {
add = false;
}
}
if (add) {
if (minuteKey in cards[dayKey][hour]) {
if (
!cards[dayKey][hour][minuteKey].uniqueKeys.includes(
uniqueKey
) ||
detailLevel == "full"
) {
cards[dayKey][hour][minuteKey].entries.push(i);
cards[dayKey][hour][minuteKey].uniqueKeys.push(uniqueKey);
}
} else {
cards[dayKey][hour][minuteKey] = {
camera: i.camera,
time: time.getTime() / 1000,
entries: [i],
uniqueKeys: [uniqueKey],
};
}
}
});
});
});
return cards;
}