Add external sub label as timeline entry (#8855)

* Add external sub label to timeline

* Include icon

* Update timeline.py

Co-authored-by: Sergey Krashevich <svk@svk.su>

* Formatting

---------

Co-authored-by: Sergey Krashevich <svk@svk.su>
This commit is contained in:
Nicolas Mowen 2023-12-05 06:04:22 -07:00 committed by Blake Blackshear
parent c716e4b1cb
commit b1cd5f0926
2 changed files with 33 additions and 2 deletions

View File

@ -7,6 +7,7 @@ from multiprocessing import Queue
from multiprocessing.synchronize import Event as MpEvent from multiprocessing.synchronize import Event as MpEvent
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.const import ALL_ATTRIBUTE_LABELS
from frigate.events.maintainer import EventTypeEnum from frigate.events.maintainer import EventTypeEnum
from frigate.models import Timeline from frigate.models import Timeline
from frigate.util.builtin import to_relative_box from frigate.util.builtin import to_relative_box
@ -101,6 +102,13 @@ class TimelineProcessor(threading.Thread):
event_data["attributes"].keys() event_data["attributes"].keys()
)[0] )[0]
Timeline.insert(timeline_entry).execute() Timeline.insert(timeline_entry).execute()
elif not prev_event_data.get("sub_label") and event_data.get("sub_label"):
sub_label = event_data["sub_label"][0]
if sub_label not in ALL_ATTRIBUTE_LABELS:
timeline_entry[Timeline.class_type] = "sub_label"
timeline_entry[Timeline.data]["sub_label"] = sub_label
Timeline.insert(timeline_entry).execute()
elif event_type == "end": elif event_type == "end":
if event_data["has_clip"] or event_data["has_snapshot"]: if event_data["has_clip"] or event_data["has_snapshot"]:
timeline_entry[Timeline.class_type] = "gone" timeline_entry[Timeline.class_type] = "gone"

View File

@ -145,6 +145,13 @@ function getTimelineIcon(timelineItem) {
default: default:
return <DeliveryTruckIcon className="w-8" />; return <DeliveryTruckIcon className="w-8" />;
} }
case 'sub_label':
switch (timelineItem.data.label) {
case 'person':
return <FaceIcon className="w-8" />;
case 'car':
return <LicensePlateIcon className="w-8" />;
}
} }
} }
@ -176,8 +183,24 @@ function getTimelineItemDescription(config, timelineItem, event) {
time_style: 'medium', time_style: 'medium',
time_format: config.ui.time_format, time_format: config.ui.time_format,
})}`; })}`;
case 'attribute': case 'attribute': {
return `${timelineItem.data.attribute.replaceAll("_", " ")} detected for ${event.label} at ${formatUnixTimestampToDateTime( let title = "";
if (timelineItem.data.attribute == 'face' || timelineItem.data.attribute == 'license_plate') {
title = `${timelineItem.data.attribute.replaceAll("_", " ")} detected for ${event.label}`;
} else {
title = `${event.label} recognized as ${timelineItem.data.attribute.replaceAll("_", " ")}`
}
return `${title} at ${formatUnixTimestampToDateTime(
timelineItem.timestamp,
{
date_style: 'short',
time_style: 'medium',
time_format: config.ui.time_format,
}
)}`;
}
case 'sub_label':
return `${event.label} recognized as ${timelineItem.data.sub_label} at ${formatUnixTimestampToDateTime(
timelineItem.timestamp, timelineItem.timestamp,
{ {
date_style: 'short', date_style: 'short',