mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-07 11:45:24 +03:00
reduce duplicate items and improve time format
This commit is contained in:
parent
a7f4f9919d
commit
8d143dc655
@ -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",
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ type Card = {
|
|||||||
camera: string,
|
camera: string,
|
||||||
time: number,
|
time: number,
|
||||||
entries: Timeline[],
|
entries: Timeline[],
|
||||||
|
uniqueKeys: string[],
|
||||||
}
|
}
|
||||||
|
|
||||||
type Preview = {
|
type Preview = {
|
||||||
|
|||||||
88
web/src/utils/historyUtil.ts
Normal file
88
web/src/utils/historyUtil.ts
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user