From 2d71cd7fe21e0f470141553d58671d51e0e5872a Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 22 Apr 2024 20:20:30 -0600 Subject: [PATCH] Improve review mqtt topic (#11072) * Don't request preview for current hour and fix content type * Send before / after on messages * Send before / after for end * Handle specific cases * remove log * Fix update type --- frigate/api/media.py | 2 +- frigate/review/maintainer.py | 59 +++++++++++++++---- web/src/components/card/AnimatedEventCard.tsx | 7 ++- web/src/types/ws.ts | 3 +- web/src/views/live/LiveDashboardView.tsx | 15 ++++- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/frigate/api/media.py b/frigate/api/media.py index 9770de157..519467643 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -1351,6 +1351,6 @@ def preview_thumbnail(file_name: str): ) response = make_response(jpg_bytes) - response.headers["Content-Type"] = "image/jpeg" + response.headers["Content-Type"] = "image/webp" response.headers["Cache-Control"] = "private, max-age=31536000" return response diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index 5e5138083..750ed44ba 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -146,25 +146,61 @@ class ReviewSegmentMaintainer(threading.Thread): self.stop_event = stop_event - def update_segment(self, segment: PendingReviewSegment) -> None: - """Update segment.""" - seg_data = segment.get_data(ended=False) - self.requestor.send_data(UPSERT_REVIEW_SEGMENT, seg_data) + def new_segment( + self, + segment: PendingReviewSegment, + ) -> None: + """New segment.""" + new_data = segment.get_data(ended=False) + self.requestor.send_data(UPSERT_REVIEW_SEGMENT, new_data) + start_data = {k.name: v for k, v in new_data.items()} self.requestor.send_data( "reviews", json.dumps( - {"type": "update", "review": {k.name: v for k, v in seg_data.items()}} + { + "type": "new", + "before": start_data, + "after": start_data, + } + ), + ) + + def update_segment( + self, + segment: PendingReviewSegment, + camera_config: CameraConfig, + frame, + objects: list[TrackedObject], + ) -> None: + """Update segment.""" + prev_data = segment.get_data(ended=False) + segment.update_frame(camera_config, frame, objects) + new_data = segment.get_data(ended=False) + self.requestor.send_data(UPSERT_REVIEW_SEGMENT, new_data) + self.requestor.send_data( + "reviews", + json.dumps( + { + "type": "update", + "before": {k.name: v for k, v in prev_data.items()}, + "after": {k.name: v for k, v in new_data.items()}, + } ), ) def end_segment(self, segment: PendingReviewSegment) -> None: """End segment.""" - seg_data = segment.get_data(ended=True) - self.requestor.send_data(UPSERT_REVIEW_SEGMENT, seg_data) + final_data = segment.get_data(ended=True) + self.requestor.send_data(UPSERT_REVIEW_SEGMENT, final_data) + end_data = {k.name: v for k, v in final_data.items()} self.requestor.send_data( "reviews", json.dumps( - {"type": "end", "review": {k.name: v for k, v in seg_data.items()}} + { + "type": "end", + "before": end_data, + "after": end_data, + } ), ) self.active_review_segments[segment.camera] = None @@ -219,9 +255,10 @@ class ReviewSegmentMaintainer(threading.Thread): yuv_frame = self.frame_manager.get( frame_id, camera_config.frame_shape_yuv ) - segment.update_frame(camera_config, yuv_frame, active_objects) + self.update_segment( + segment, camera_config, yuv_frame, active_objects + ) self.frame_manager.close(frame_id) - self.update_segment(segment) except FileNotFoundError: return else: @@ -317,7 +354,7 @@ class ReviewSegmentMaintainer(threading.Thread): camera_config, yuv_frame, active_objects ) self.frame_manager.close(frame_id) - self.update_segment(self.active_review_segments[camera]) + self.new_segment(self.active_review_segments[camera]) except FileNotFoundError: return diff --git a/web/src/components/card/AnimatedEventCard.tsx b/web/src/components/card/AnimatedEventCard.tsx index 4e27ad54f..dddbcdb77 100644 --- a/web/src/components/card/AnimatedEventCard.tsx +++ b/web/src/components/card/AnimatedEventCard.tsx @@ -12,6 +12,7 @@ import { InProgressPreview, VideoPreview, } from "../player/PreviewThumbnailPlayer"; +import { isCurrentHour } from "@/utils/dateUtil"; type AnimatedEventCardProps = { event: ReviewSegment; @@ -19,10 +20,14 @@ type AnimatedEventCardProps = { export function AnimatedEventCard({ event }: AnimatedEventCardProps) { const { data: config } = useSWR("config"); + const currentHour = useMemo(() => isCurrentHour(event.start_time), [event]); + // preview const { data: previews } = useSWR( - `/preview/${event.camera}/start/${Math.round(event.start_time)}/end/${Math.round(event.end_time || event.start_time + 20)}`, + currentHour + ? null + : `/preview/${event.camera}/start/${Math.round(event.start_time)}/end/${Math.round(event.end_time || event.start_time + 20)}`, ); // interaction diff --git a/web/src/types/ws.ts b/web/src/types/ws.ts index 8e86604b3..177d3600a 100644 --- a/web/src/types/ws.ts +++ b/web/src/types/ws.ts @@ -31,7 +31,8 @@ type FrigateObjectState = { export interface FrigateReview { type: "new" | "update" | "end"; - review: ReviewSegment; + before: ReviewSegment; + after: ReviewSegment; } export interface FrigateEvent { diff --git a/web/src/views/live/LiveDashboardView.tsx b/web/src/views/live/LiveDashboardView.tsx index 7cd6bbcd6..3c186656a 100644 --- a/web/src/views/live/LiveDashboardView.tsx +++ b/web/src/views/live/LiveDashboardView.tsx @@ -47,8 +47,19 @@ export default function LiveDashboardView({ } // if event is ended and was saved, update events list - if (eventUpdate.review.severity == "alert") { - setTimeout(() => updateEvents(), eventUpdate.type == "end" ? 1000 : 6000); + if (eventUpdate.after.severity == "alert") { + if (eventUpdate.type == "end" || eventUpdate.type == "new") { + setTimeout( + () => updateEvents(), + eventUpdate.type == "end" ? 1000 : 6000, + ); + } else if ( + eventUpdate.before.data.objects.length < + eventUpdate.after.data.objects.length + ) { + setTimeout(() => updateEvents(), 5000); + } + return; } }, [eventUpdate, updateEvents]);