feat: Add support for Frigate reviews / detections [initial PR] (#2315)

- Add support for Frigate reviews / detections.
 - Add support for GenAI metadata.
- Significant internal refactor to more flexible "UnifiedQuery" to allow
mixing cameras with simple metadata and review metadata (e.g. a timeline
view of a Frigate camera with reviews, and a Reolink camera with simple
metadata).
 - Add support for folder media as camera media.

There are a few more PRs to commit prior to this going live, but
commiting this for now due to the scale of the change.

BREAKING CHANGE: `media_type` and `events_type` are retired under
`live`, `viewer` and `timeline` configuration sections, instead media
type is associated (once) with the camera under `media`.
This commit is contained in:
Dermot Duffy
2026-01-19 13:32:50 -08:00
committed by GitHub
parent 6eb0a87ca8
commit fc32727860
215 changed files with 14491 additions and 6160 deletions
+53 -16
View File
@@ -1,7 +1,8 @@
import { ExpiringEqualityCache } from '../cache/expiring-cache';
import { SSLCiphers } from '../config/schema/cameras';
import { AdvancedCameraCardView } from '../config/schema/common/const';
import { CapabilityKey, Endpoint, Icon } from '../types';
import { BaseQuery, QueryFilters, QuerySource } from '../query-source';
import { CapabilityKey, Endpoint, Icon, Severity } from '../types';
import { ViewMedia } from '../view/item';
// ====
@@ -13,6 +14,7 @@ export enum QueryType {
Recording = 'recording-query',
RecordingSegments = 'recording-segments-query',
MediaMetadata = 'media-metadata',
Review = 'review-query',
}
export enum QueryResultsType {
@@ -20,6 +22,7 @@ export enum QueryResultsType {
Recording = 'recording-results',
RecordingSegments = 'recording-segments-results',
MediaMetadata = 'media-metadata-results',
Review = 'review-results',
}
export enum Engine {
@@ -46,10 +49,12 @@ interface LimitedDataQuery {
}
export interface MediaQuery
extends CameraQuery,
extends BaseQuery,
CameraQuery,
QueryFilters,
Partial<TimeBasedDataQuery>,
Partial<LimitedDataQuery> {
favorite?: boolean;
source: QuerySource.Camera;
}
export interface QueryResults {
@@ -74,14 +79,18 @@ export type QueryReturnType<QT> = QT extends EventQuery
? RecordingSegmentsQueryResults
: QT extends MediaMetadataQuery
? MediaMetadataQueryResults
: never;
: QT extends ReviewQuery
? ReviewQueryResults
: never;
export type PartialQueryConcreteType<PQT> = PQT extends PartialEventQuery
? EventQuery
: PQT extends PartialRecordingQuery
? RecordingQuery
: PQT extends PartialRecordingSegmentsQuery
? RecordingSegmentsQuery
: never;
: PQT extends PartialReviewQuery
? ReviewQuery
: never;
export type ResultsMap<QT> = Map<QT, QueryReturnType<QT>>;
export type EventQueryResultsMap = ResultsMap<EventQuery>;
@@ -140,16 +149,21 @@ export interface EngineOptions {
export interface CameraEvent {
cameraID: string;
type: 'new' | 'update' | 'end';
type:
| 'new' // A new event has started.
| 'update' // An update for an event is available (except GenAI).
| 'end' // An event has ended.
| 'genai'; // An AI based update is available.
// When fidelity is `high`, the engine is assumed to provide exact details of
// what new media is available. Otherwise all media types are assumed to be
// possibly newly available.
fidelity?: 'high' | 'low';
// Whether a new clip/snapshot/recording may be available.
// Whether new media may be available.
clip?: boolean;
snapshot?: boolean;
review?: boolean;
}
export type CameraEventCallback = (ev: CameraEvent) => void;
@@ -158,6 +172,21 @@ export class CameraManagerRequestCache extends ExpiringEqualityCache<
QueryResults
> {}
// ====================
// Default Query Params
// ====================
/**
* Default query parameters that engines can provide based on camera configuration.
*/
export interface DefaultQueryParameters {
// Object labels (what was detected)
what?: Set<string>;
// Zones (where detection occurred)
where?: Set<string>;
}
// ===========
// Event Query
// ===========
@@ -170,15 +199,6 @@ export interface EventQuery extends MediaQuery {
// Frigate equivalent: has_clip
hasClip?: boolean;
// Frigate equivalent: label
what?: Set<string>;
// Frigate equivalent: sub_label
tags?: Set<string>;
// Frigate equivalent: zone
where?: Set<string>;
}
export type PartialEventQuery = Partial<EventQuery>;
@@ -225,3 +245,20 @@ export interface MediaMetadataQueryResults extends QueryResults {
type: QueryResultsType.MediaMetadata;
metadata: MediaMetadata;
}
// ============
// Review Query
// ============
export interface ReviewQuery extends MediaQuery {
type: QueryType.Review;
severity?: Severity;
}
export type PartialReviewQuery = Partial<ReviewQuery>;
export interface ReviewQueryResults extends QueryResults {
type: QueryResultsType.Review;
}
export type ReviewQueryResultsMap = ResultsMap<ReviewQuery>;