From cb9dee3dc96f0e67075249597cc41787a06fe5e4 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:10:01 -0600 Subject: [PATCH] event endpoints --- .../api/defs/query/events_query_parameters.py | 3 ++ frigate/api/event.py | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/frigate/api/defs/query/events_query_parameters.py b/frigate/api/defs/query/events_query_parameters.py index 187dd3f91..8e5a5391a 100644 --- a/frigate/api/defs/query/events_query_parameters.py +++ b/frigate/api/defs/query/events_query_parameters.py @@ -12,6 +12,7 @@ class EventsQueryParams(BaseModel): labels: Optional[str] = "all" sub_label: Optional[str] = "all" sub_labels: Optional[str] = "all" + attributes: Optional[str] = "all" zone: Optional[str] = "all" zones: Optional[str] = "all" limit: Optional[int] = 100 @@ -58,6 +59,8 @@ class EventsSearchQueryParams(BaseModel): limit: Optional[int] = 50 cameras: Optional[str] = "all" labels: Optional[str] = "all" + sub_labels: Optional[str] = "all" + attributes: Optional[str] = "all" zones: Optional[str] = "all" after: Optional[float] = None before: Optional[float] = None diff --git a/frigate/api/event.py b/frigate/api/event.py index fc78ac0e5..520e6e305 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -99,6 +99,8 @@ def events( if sub_labels == "all" and sub_label != "all": sub_labels = sub_label + attributes = unquote(params.attributes) + zone = params.zone zones = params.zones @@ -187,6 +189,17 @@ def events( sub_label_clause = reduce(operator.or_, sub_label_clauses) clauses.append((sub_label_clause)) + if attributes != "all": + # Custom classification results are stored as data[model_name] = result_value + filtered_attributes = attributes.split(",") + attribute_clauses = [] + + for attr in filtered_attributes: + attribute_clauses.append(Event.data.cast("text") % f'*:"{attr}"*') + + attribute_clause = reduce(operator.or_, attribute_clauses) + clauses.append(attribute_clause) + if recognized_license_plate != "all": filtered_recognized_license_plates = recognized_license_plate.split(",") @@ -492,6 +505,8 @@ def events_search( # Filters cameras = params.cameras labels = params.labels + sub_labels = params.sub_labels + attributes = params.attributes zones = params.zones after = params.after before = params.before @@ -566,6 +581,38 @@ def events_search( if labels != "all": event_filters.append((Event.label << labels.split(","))) + if sub_labels != "all": + # use matching so joined sub labels are included + # for example a sub label 'bob' would get events + # with sub labels 'bob' and 'bob, john' + sub_label_clauses = [] + filtered_sub_labels = sub_labels.split(",") + + if "None" in filtered_sub_labels: + filtered_sub_labels.remove("None") + sub_label_clauses.append((Event.sub_label.is_null())) + + for label in filtered_sub_labels: + sub_label_clauses.append( + (Event.sub_label.cast("text") == label) + ) # include exact matches + + # include this label when part of a list + sub_label_clauses.append((Event.sub_label.cast("text") % f"*{label},*")) + sub_label_clauses.append((Event.sub_label.cast("text") % f"*, {label}*")) + + event_filters.append((reduce(operator.or_, sub_label_clauses))) + + if attributes != "all": + # Custom classification results are stored as data[model_name] = result_value + filtered_attributes = attributes.split(",") + attribute_clauses = [] + + for attr in filtered_attributes: + attribute_clauses.append(Event.data.cast("text") % f'*:"{attr}"*') + + event_filters.append(reduce(operator.or_, attribute_clauses)) + if zones != "all": zone_clauses = [] filtered_zones = zones.split(",")