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
+26 -2
View File
@@ -2,8 +2,9 @@ import { z } from 'zod';
import type { EffectOptions } from './components-lib/effects/types';
import type { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from './ha/types';
export type ClipsOrSnapshots = 'clips' | 'snapshots';
export type ClipsOrSnapshotsOrAll = 'clips' | 'snapshots' | 'all';
// UI-facing media types for galleries and views.
export const VIEW_MEDIA_TYPES = ['clips', 'snapshots', 'recordings', 'reviews'] as const;
export type ViewMediaType = (typeof VIEW_MEDIA_TYPES)[number];
export class AdvancedCameraCardError extends Error {
context?: unknown;
@@ -62,6 +63,24 @@ export interface Message {
url?: MessageURL;
}
export interface MetadataField {
title: string;
icon?: Icon;
hint?: string;
emphasis?: Severity;
}
export interface OverlayMessageControl extends MetadataField {
callback: () => OverlayMessage | null | Promise<OverlayMessage | null>;
}
export interface OverlayMessage {
heading?: MetadataField;
controls?: OverlayMessageControl[];
details?: MetadataField[];
text?: string;
}
export type WebkitHTMLVideoElement = HTMLVideoElement & {
webkitDisplayingFullscreen: boolean;
webkitSupportsFullscreen: boolean;
@@ -124,6 +143,7 @@ export interface CapabilitiesRaw {
clips?: boolean;
recordings?: boolean;
snapshots?: boolean;
reviews?: boolean;
'favorite-events'?: boolean;
'favorite-recordings'?: boolean;
@@ -151,6 +171,7 @@ export const capabilityKeys: readonly [CapabilityKey, ...CapabilityKey[]] = [
'menu',
'ptz',
'recordings',
'reviews',
'seek',
'snapshots',
'substream',
@@ -194,3 +215,6 @@ export interface EffectsControllerAPI {
stopEffect(effect: EffectName): void;
toggleEffect(effect: EffectName, options?: EffectOptions): Promise<void>;
}
export const SEVERITIES = ['high', 'medium', 'low'] as const;
export type Severity = (typeof SEVERITIES)[number];