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:
+54
-1
@@ -1,9 +1,13 @@
|
||||
import { clone } from 'lodash-es';
|
||||
import { FolderPathComponent } from '../card-controller/folders/types';
|
||||
import { FolderConfig } from '../config/schema/folders';
|
||||
import { Severity } from '../types';
|
||||
|
||||
export enum ViewMediaType {
|
||||
Clip = 'clip',
|
||||
Snapshot = 'snapshot',
|
||||
Recording = 'recording',
|
||||
Review = 'review',
|
||||
}
|
||||
|
||||
export enum VideoContentType {
|
||||
@@ -14,6 +18,7 @@ export enum VideoContentType {
|
||||
export interface ViewMediaSourceOptions {
|
||||
cameraID?: string;
|
||||
folder?: FolderConfig;
|
||||
path?: readonly FolderPathComponent[];
|
||||
}
|
||||
|
||||
export class ViewMedia {
|
||||
@@ -59,6 +64,9 @@ export class ViewMedia {
|
||||
public getTitle(): string | null {
|
||||
return null;
|
||||
}
|
||||
public getDescription(): string | null {
|
||||
return null;
|
||||
}
|
||||
public getThumbnail(): string | null {
|
||||
return null;
|
||||
}
|
||||
@@ -68,6 +76,9 @@ export class ViewMedia {
|
||||
public isFavorite(): boolean | null {
|
||||
return null;
|
||||
}
|
||||
public isReviewed(): boolean | null {
|
||||
return null;
|
||||
}
|
||||
public includesTime(seek: Date): boolean {
|
||||
const startTime = this.getStartTime();
|
||||
const endTime = this.getUsableEndTime();
|
||||
@@ -80,9 +91,25 @@ export class ViewMedia {
|
||||
public setFavorite(_favorite: boolean): void {
|
||||
return;
|
||||
}
|
||||
public getSeverity(): Severity | null {
|
||||
return null;
|
||||
}
|
||||
public getWhere(): string[] | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of this ViewMedia instance.
|
||||
*
|
||||
* This is needed because Lit components use reference equality (===) to
|
||||
* detect property changes. When we mutate an item's state (e.g.,
|
||||
* setReviewed), the reference doesn't change, so Lit doesn't re-render. By
|
||||
* cloning the item before mutation and replacing it in the QueryResults, we
|
||||
* ensure Lit sees a new reference and updates the UI.
|
||||
*/
|
||||
public clone(): this {
|
||||
return clone(this);
|
||||
}
|
||||
}
|
||||
|
||||
export interface EventViewMedia extends ViewMedia {
|
||||
@@ -96,6 +123,12 @@ export interface RecordingViewMedia extends ViewMedia {
|
||||
getEventCount(): number | null;
|
||||
}
|
||||
|
||||
export interface ReviewViewMedia extends ViewMedia {
|
||||
getWhat(): string[] | null;
|
||||
isReviewed(): boolean | null;
|
||||
setReviewed(reviewed: boolean): void;
|
||||
}
|
||||
|
||||
interface ViewFolderParameters {
|
||||
icon?: string | null;
|
||||
id?: string | null;
|
||||
@@ -105,14 +138,20 @@ interface ViewFolderParameters {
|
||||
|
||||
export class ViewFolder {
|
||||
private _folder: FolderConfig;
|
||||
private _path: readonly FolderPathComponent[];
|
||||
|
||||
private _icon: string | null;
|
||||
private _id: string | null;
|
||||
private _title: string | null;
|
||||
private _thumbnail: string | null;
|
||||
|
||||
constructor(folder: FolderConfig, params?: ViewFolderParameters) {
|
||||
constructor(
|
||||
folder: FolderConfig,
|
||||
path: readonly FolderPathComponent[],
|
||||
params?: ViewFolderParameters,
|
||||
) {
|
||||
this._folder = folder;
|
||||
this._path = path;
|
||||
|
||||
this._icon = params?.icon ?? null;
|
||||
this._id = params?.id ?? null;
|
||||
@@ -123,21 +162,35 @@ export class ViewFolder {
|
||||
public getFolder(): FolderConfig {
|
||||
return this._folder;
|
||||
}
|
||||
public getPath(): readonly FolderPathComponent[] {
|
||||
return this._path;
|
||||
}
|
||||
public getID(): string | null {
|
||||
return this._id;
|
||||
}
|
||||
public getTitle(): string | null {
|
||||
return this._title;
|
||||
}
|
||||
public getDescription(): string | null {
|
||||
return null;
|
||||
}
|
||||
public getThumbnail(): string | null {
|
||||
return this._thumbnail;
|
||||
}
|
||||
public getIcon(): string | null {
|
||||
return this._icon;
|
||||
}
|
||||
public getSeverity(): Severity | null {
|
||||
return null;
|
||||
}
|
||||
public isFavorite(): boolean | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** See ViewMedia.clone() for explanation. */
|
||||
public clone(): this {
|
||||
return clone(this);
|
||||
}
|
||||
}
|
||||
|
||||
export type ViewItem = ViewMedia | ViewFolder;
|
||||
|
||||
Reference in New Issue
Block a user