Event cleanup (#11225)

* remove duplicate event purging

* Slightly increase stationary object sensitivity

* Add toast for export starting

* Increase stationary threshold as well

* Update message

* Make text consistent

* Update message
This commit is contained in:
Nicolas Mowen 2024-05-03 08:03:41 -06:00 committed by GitHub
parent e7950abec3
commit 216e44bc34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 32 additions and 46 deletions

View File

@ -184,43 +184,6 @@ class EventCleanup(threading.Thread):
Event.update(update_params).where(Event.id << events_to_update).execute()
return events_to_update
def purge_duplicates(self) -> None:
duplicate_query = """with grouped_events as (
select id,
label,
camera,
has_snapshot,
has_clip,
end_time,
row_number() over (
partition by label, camera, round(start_time/5,0)*5
order by end_time-start_time desc
) as copy_number
from event
)
select distinct id, camera, has_snapshot, has_clip from grouped_events
where copy_number > 1 and end_time not null;"""
duplicate_events: list[Event] = Event.raw(duplicate_query)
for event in duplicate_events:
logger.debug(f"Removing duplicate: {event.id}")
try:
media_name = f"{event.camera}-{event.id}"
media_path = Path(f"{os.path.join(CLIPS_DIR, media_name)}.jpg")
media_path.unlink(missing_ok=True)
media_path = Path(f"{os.path.join(CLIPS_DIR, media_name)}-clean.png")
media_path.unlink(missing_ok=True)
except OSError as e:
logger.warning(f"Unable to delete event images: {e}")
(
Event.delete()
.where(Event.id << [event.id for event in duplicate_events])
.execute()
)
def run(self) -> None:
# only expire events every 5 minutes
while not self.stop_event.wait(300):
@ -232,7 +195,6 @@ class EventCleanup(threading.Thread):
).execute()
self.expire(EventCleanupType.snapshots)
self.purge_duplicates()
# drop events from db where has_clip and has_snapshot are false
delete_query = Event.delete().where(

View File

@ -22,8 +22,8 @@ from frigate.util.object import average_boxes, median_of_boxes
logger = logging.getLogger(__name__)
THRESHOLD_ACTIVE_IOU = 0.2
THRESHOLD_STATIONARY_IOU = 0.6
THRESHOLD_ACTIVE_IOU = 0.35
THRESHOLD_STATIONARY_IOU = 0.7
MAX_STATIONARY_HISTORY = 10

View File

@ -186,11 +186,11 @@ export default function HlsVideoPlayer({
const resp = await onUploadFrame(videoRef.current.currentTime);
if (resp && resp.status == 200) {
toast.success("Successfully submitted frame to Frigate Plus", {
toast.success("Successfully submitted frame to Frigate+", {
position: "top-center",
});
} else {
toast.success("Failed to submit frame to Frigate Plus", {
toast.success("Failed to submit frame to Frigate+", {
position: "top-center",
});
}

View File

@ -45,6 +45,8 @@ import { useCameraMotionNextTimestamp } from "@/hooks/use-camera-activity";
import useOptimisticState from "@/hooks/use-optimistic-state";
import { Skeleton } from "@/components/ui/skeleton";
import scrollIntoView from "scroll-into-view-if-needed";
import { Toaster } from "@/components/ui/sonner";
import { toast } from "sonner";
type EventViewProps = {
reviews?: ReviewSegment[];
@ -194,10 +196,31 @@ export default function EventView({
return;
}
axios.post(
axios
.post(
`export/${review.camera}/start/${review.start_time}/end/${review.end_time}`,
{ playback: "realtime" },
)
.then((response) => {
if (response.status == 200) {
toast.success(
"Successfully started export. View the file in the /exports folder.",
{ position: "top-center" },
);
}
})
.catch((error) => {
if (error.response?.data?.message) {
toast.error(
`Failed to start export: ${error.response.data.message}`,
{ position: "top-center" },
);
} else {
toast.error(`Failed to start export: ${error.message}`, {
position: "top-center",
});
}
});
},
[reviewItems],
);
@ -215,6 +238,7 @@ export default function EventView({
return (
<div className="py-2 flex flex-col size-full">
<Toaster />
<div className="h-11 mb-2 pl-3 pr-2 relative flex justify-between items-center">
{isMobile && (
<Logo className="absolute inset-x-1/2 -translate-x-1/2 h-8" />