Add support for 'scroll up refresh' in the gallery.

This commit is contained in:
Dermot Duffy
2023-03-06 21:04:05 -08:00
parent e5445284e5
commit 7f1fcf454e
11 changed files with 245 additions and 52 deletions
+6
View File
@@ -23,6 +23,7 @@ import {
CameraEndpoints,
MediaMetadataQuery,
MediaMetadataQueryResultsMap,
EngineOptions,
} from './types';
export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000;
@@ -58,18 +59,21 @@ export interface CameraManagerEngine {
hass: HomeAssistant,
cameras: CameraConfigs,
query: EventQuery,
engineOptions?: EngineOptions,
): Promise<EventQueryResultsMap | null>;
getRecordings(
hass: HomeAssistant,
cameras: CameraConfigs,
query: RecordingQuery,
engineOptions?: EngineOptions,
): Promise<RecordingQueryResultsMap | null>;
getRecordingSegments(
hass: HomeAssistant,
cameras: CameraConfigs,
query: RecordingSegmentsQuery,
engineOptions?: EngineOptions,
): Promise<RecordingSegmentsQueryResultsMap | null>;
generateMediaFromEvents(
@@ -102,12 +106,14 @@ export interface CameraManagerEngine {
cameras: CameraConfigs,
media: ViewMedia,
target: Date,
engineOptions?: EngineOptions,
): Promise<number | null>;
getMediaMetadata(
hass: HomeAssistant,
cameras: CameraConfigs,
query: MediaMetadataQuery,
engineOptions?: EngineOptions,
): Promise<MediaMetadataQueryResultsMap | null>;
getCameraMetadata(
+38 -13
View File
@@ -39,6 +39,7 @@ import {
MediaMetadataQuery,
MediaMetadataQueryResults,
MediaMetadataQueryResultsMap,
EngineOptions,
} from '../types';
import {
FrigateEventQueryResults,
@@ -426,6 +427,7 @@ export class FrigateCameraManagerEngine
hass: HomeAssistant,
cameras: CameraConfigs,
query: EventQuery,
engineOptions?: EngineOptions,
): Promise<EventQueryResultsMap | null> {
const output: EventQueryResultsMap = new Map();
@@ -437,7 +439,8 @@ export class FrigateCameraManagerEngine
return;
}
const instanceQuery = { ...query, cameraIDs: cameraIDs };
const cachedResult = this._requestCache.get(instanceQuery);
const cachedResult =
engineOptions?.useCache ?? true ? this._requestCache.get(instanceQuery) : null;
if (cachedResult) {
output.set(query, cachedResult as EventQueryResults);
return;
@@ -467,7 +470,9 @@ export class FrigateCameraManagerEngine
cached: false,
};
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
if (engineOptions?.useCache ?? true) {
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
}
output.set(instanceQuery, result);
};
@@ -491,6 +496,7 @@ export class FrigateCameraManagerEngine
hass: HomeAssistant,
cameras: CameraConfigs,
query: RecordingQuery,
engineOptions?: EngineOptions,
): Promise<RecordingQueryResultsMap | null> {
const output: RecordingQueryResultsMap = new Map();
@@ -499,7 +505,8 @@ export class FrigateCameraManagerEngine
cameraID: string,
): Promise<void> => {
const query = { ...baseQuery, cameraIDs: new Set([cameraID]) };
const cachedResult = this._requestCache.get(query);
const cachedResult =
engineOptions?.useCache ?? true ? this._requestCache.get(query) : null;
if (cachedResult) {
output.set(query, cachedResult as RecordingQueryResults);
return;
@@ -557,7 +564,9 @@ export class FrigateCameraManagerEngine
}),
cached: false,
};
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
if (engineOptions?.useCache ?? true) {
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
}
output.set(query, result);
};
@@ -573,6 +582,7 @@ export class FrigateCameraManagerEngine
hass: HomeAssistant,
cameras: CameraConfigs,
query: RecordingSegmentsQuery,
engineOptions?: EngineOptions,
): Promise<RecordingSegmentsQueryResultsMap | null> {
const output: RecordingSegmentsQueryResultsMap = new Map();
@@ -595,7 +605,10 @@ export class FrigateCameraManagerEngine
// query is different -- the segments won't be). This is since the
// volume of data in segment transfers can be high, and the segments can
// be used in high frequency situations (e.g. video seeking).
const cachedSegments = this._recordingSegmentsCache.get(cameraID, range);
const cachedSegments =
engineOptions?.useCache ?? true
? this._recordingSegmentsCache.get(cameraID, range)
: null;
if (cachedSegments) {
output.set(query, <FrigateRecordingSegmentsQueryResults>{
type: QueryResultsType.RecordingSegments,
@@ -615,7 +628,10 @@ export class FrigateCameraManagerEngine
};
const segments = await getRecordingSegments(hass, request);
this._recordingSegmentsCache.add(cameraID, range, segments);
if (engineOptions?.useCache ?? true) {
this._recordingSegmentsCache.add(cameraID, range, segments);
}
output.set(query, <FrigateRecordingSegmentsQueryResults>{
type: QueryResultsType.RecordingSegments,
@@ -757,6 +773,7 @@ export class FrigateCameraManagerEngine
cameras: CameraConfigs,
media: ViewMedia,
target: Date,
engineOptions?: EngineOptions,
): Promise<number | null> {
const start = media.getStartTime();
const end = media.getEndTime();
@@ -772,7 +789,7 @@ export class FrigateCameraManagerEngine
type: QueryType.RecordingSegments,
};
const results = await this.getRecordingSegments(hass, cameras, query);
const results = await this.getRecordingSegments(hass, cameras, query, engineOptions);
if (results) {
return this._getSeekTimeInSegments(
@@ -811,9 +828,10 @@ export class FrigateCameraManagerEngine
hass: HomeAssistant,
cameras: CameraConfigs,
query: MediaMetadataQuery,
engineOptions?: EngineOptions,
): Promise<MediaMetadataQueryResultsMap | null> {
const output: MediaMetadataQueryResultsMap = new Map();
if (this._requestCache.has(query)) {
if ((engineOptions?.useCache ?? true) && this._requestCache.has(query)) {
const cachedResult = <MediaMetadataQueryResults | null>(
this._requestCache.get(query)
);
@@ -860,10 +878,15 @@ export class FrigateCameraManagerEngine
};
const processRecordings = async (cameraIDs: Set<string>): Promise<void> => {
const recordings = await this.getRecordings(hass, cameras, {
type: QueryType.Recording,
cameraIDs: cameraIDs,
});
const recordings = await this.getRecordings(
hass,
cameras,
{
type: QueryType.Recording,
cameraIDs: cameraIDs,
},
engineOptions,
);
if (!recordings) {
return;
}
@@ -902,7 +925,9 @@ export class FrigateCameraManagerEngine
cached: false,
};
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
if (engineOptions?.useCache ?? true) {
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
}
output.set(query, result);
return output;
}
+6 -1
View File
@@ -9,7 +9,6 @@ import {
DataQuery,
EventQuery,
EventQueryResultsMap,
MediaMetadata,
PartialEventQuery,
PartialRecordingQuery,
PartialRecordingSegmentsQuery,
@@ -25,6 +24,7 @@ import {
CameraEndpoints,
MediaMetadataQuery,
MediaMetadataQueryResultsMap,
EngineOptions,
} from '../types';
import { getEntityIcon, getEntityTitle } from '../../utils/ha';
import { EntityRegistryManager } from '../../utils/ha/entity-registry';
@@ -71,6 +71,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
_hass: HomeAssistant,
_cameras: CameraConfigs,
_query: EventQuery,
_engineOptions?: EngineOptions,
): Promise<EventQueryResultsMap | null> {
return null;
}
@@ -79,6 +80,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
_hass: HomeAssistant,
_cameras: CameraConfigs,
_query: RecordingQuery,
_engineOptions?: EngineOptions,
): Promise<RecordingQueryResultsMap | null> {
return null;
}
@@ -87,6 +89,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
_hass: HomeAssistant,
_cameras: CameraConfigs,
_query: RecordingSegmentsQuery,
_engineOptions?: EngineOptions,
): Promise<RecordingSegmentsQueryResultsMap | null> {
return null;
}
@@ -134,6 +137,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
_cameras: CameraConfigs,
_media: ViewMedia,
_target: Date,
_engineOptions?: EngineOptions,
): Promise<number | null> {
return null;
}
@@ -142,6 +146,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
_hass: HomeAssistant,
_cameras: CameraConfigs,
_query: MediaMetadataQuery,
_engineOptions?: EngineOptions,
): Promise<MediaMetadataQueryResultsMap | null> {
return null;
}
+16 -5
View File
@@ -33,6 +33,7 @@ import {
Engine,
MediaMetadataQuery,
MediaMetadataQueryResults,
EngineOptions,
} from './types.js';
import orderBy from 'lodash-es/orderBy';
import { CameraManagerEngineFactory } from './engine-factory.js';
@@ -361,31 +362,35 @@ export class CameraManager {
public async getEvents(
hass: HomeAssistant,
query: EventQuery | EventQuery[],
engineOptions?: EngineOptions,
): Promise<EventQueryResultsMap> {
return await this._handleQuery(hass, query);
return await this._handleQuery(hass, query, engineOptions);
}
public async getRecordings(
hass: HomeAssistant,
query: RecordingQuery | RecordingQuery[],
engineOptions?: EngineOptions,
): Promise<RecordingQueryResultsMap> {
return await this._handleQuery(hass, query);
return await this._handleQuery(hass, query, engineOptions);
}
public async getRecordingSegments(
hass: HomeAssistant,
query: RecordingSegmentsQuery | RecordingSegmentsQuery[],
engineOptions?: EngineOptions,
): Promise<RecordingSegmentsQueryResultsMap> {
return await this._handleQuery(hass, query);
return await this._handleQuery(hass, query, engineOptions);
}
public async executeMediaQueries<T extends MediaQuery>(
hass: HomeAssistant,
queries: T[],
engineOptions?: EngineOptions,
): Promise<ViewMedia[] | null> {
return this._convertQueryResultsToMedia(
hass,
await this._handleQuery(hass, queries),
await this._handleQuery(hass, queries, engineOptions),
);
}
@@ -394,6 +399,7 @@ export class CameraManager {
queries: T[],
results: ViewMedia[],
direction: 'earlier' | 'later',
engineOptions?: EngineOptions,
): Promise<ExtendedMediaQueryResult<T> | null> {
const getTimeFromResults = (want: 'earliest' | 'latest'): Date | null => {
let output: Date | null = null;
@@ -446,7 +452,7 @@ export class CameraManager {
const newChunkMedia = this._convertQueryResultsToMedia(
hass,
await this._handleQuery(hass, newChunkQueries),
await this._handleQuery(hass, newChunkQueries, engineOptions),
);
if (!newChunkMedia.length) {
@@ -554,6 +560,7 @@ export class CameraManager {
protected async _handleQuery<QT extends DataQuery>(
hass: HomeAssistant,
query: QT | QT[],
engineOptions?: EngineOptions,
): Promise<Map<QT, QueryReturnType<QT>>> {
const _queries = arrayify(query);
const results = new Map<QT, QueryReturnType<QT>>();
@@ -573,24 +580,28 @@ export class CameraManager {
hass,
this._store.getCameras(),
query,
engineOptions,
)) as Map<QT, QueryReturnType<QT>> | null;
} else if (QueryClassifier.isRecordingQuery(query)) {
engineResult = (await engine.getRecordings(
hass,
this._store.getCameras(),
query,
engineOptions,
)) as Map<QT, QueryReturnType<QT>> | null;
} else if (QueryClassifier.isRecordingSegmentsQuery(query)) {
engineResult = (await engine.getRecordingSegments(
hass,
this._store.getCameras(),
query,
engineOptions,
)) as Map<QT, QueryReturnType<QT>> | null;
} else if (QueryClassifier.isMediaMetadataQuery(query)) {
engineResult = (await engine.getMediaMetadata(
hass,
this._store.getCameras(),
query,
engineOptions,
)) as Map<QT, QueryReturnType<QT>> | null;
}
+5 -1
View File
@@ -130,6 +130,10 @@ export interface CameraEndpoints {
export type CameraConfigs = Map<string, CameraConfig>;
export interface EngineOptions {
useCache?: boolean;
}
// ===========
// Event Query
// ===========
@@ -148,7 +152,7 @@ export interface EventQuery extends MediaQuery {
// Frigate equivalent: sub_label
tags?: Set<string>;
// Frigate equivalent: zone
where?: Set<string>;
}