Add a performance option to control media chunk size.

This commit is contained in:
Dermot Duffy
2023-02-13 21:27:39 -08:00
parent 5910c09383
commit 03cea41675
20 changed files with 311 additions and 263 deletions
+61 -118
View File
@@ -1,7 +1,5 @@
import add from 'date-fns/add';
import sub from 'date-fns/sub';
import { ViewContext } from 'view';
import { ClipsOrSnapshotsOrAll, FrigateCardView } from '../types';
import { CardWideConfig, ClipsOrSnapshotsOrAll, FrigateCardView } from '../types';
import { View } from '../view/view';
import {
EventMediaQueries,
@@ -16,71 +14,54 @@ import { dispatchFrigateCardErrorEvent } from '../components/message';
import { MediaQueriesResults } from '../view/media-queries-results';
import { errorToConsole } from './basic';
import { MediaQuery } from '../camera-manager/types';
import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const';
export const changeViewToRecentEventsForCameraAndDependents = async (
element: HTMLElement,
hass: HomeAssistant,
cameraManager: CameraManager,
cardWideConfig: CardWideConfig,
view: View,
options?: {
mediaType?: ClipsOrSnapshotsOrAll;
targetView?: FrigateCardView;
},
): Promise<void> => {
const cameras = cameraManager.getCameras();
if (!cameras) {
return;
}
const cameraIDs = new Set(getAllDependentCameras(cameras, view.camera));
const queries = createQueriesForEventsView(cameraManager, cardWideConfig, cameraIDs, {
mediaType: options?.mediaType,
});
if (!queries) {
return;
}
(
await createViewForEvents(element, hass, cameraManager, view, {
...options,
limit: 50, // Capture the 50 most recent events.
await executeMediaQueryForView(element, hass, cameraManager, view, queries, {
targetView: options?.targetView,
})
)?.dispatchChangeEvent(element);
};
export const createViewForEvents = async (
element: HTMLElement,
hass: HomeAssistant,
const createQueriesForEventsView = (
cameraManager: CameraManager,
view: View,
cardWideConfig: CardWideConfig,
cameraIDs: Set<string>,
options?: {
query?: EventMediaQueries;
cameraIDs?: Set<string>;
mediaType?: ClipsOrSnapshotsOrAll;
targetCameraID?: string;
targetView?: FrigateCardView;
limit?: number;
},
): Promise<View | null> => {
const cameras = cameraManager.getCameras();
if (!cameras) {
return null;
}
let query: EventMediaQueries;
const cameraIDs: Set<string> = options?.cameraIDs
? options.cameraIDs
: new Set(getAllDependentCameras(cameras, view.camera));
if (options?.query) {
query = options.query;
} else {
const eventQueries = cameraManager.generateDefaultEventQueries(cameraIDs, {
...(options?.limit && { limit: options.limit }),
...(options?.mediaType === 'clips' && { hasClip: true }),
...(options?.mediaType === 'snapshots' && { hasSnapshot: true }),
});
if (!eventQueries) {
return null;
}
query = new EventMediaQueries(eventQueries);
}
if (!query) {
return null;
}
return executeMediaQueryForView(element, hass, cameraManager, view, query, {
cameraIDs: cameraIDs,
targetView: options?.targetView,
targetCameraID: options?.targetCameraID,
): EventMediaQueries | null => {
const limit =
cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT;
const eventQueries = cameraManager.generateDefaultEventQueries(cameraIDs, {
limit: limit,
...(options?.mediaType === 'clips' && { hasClip: true }),
...(options?.mediaType === 'snapshots' && { hasSnapshot: true }),
});
return eventQueries ? new EventMediaQueries(eventQueries) : null;
};
/**
@@ -96,89 +77,61 @@ export const changeViewToRecentRecordingForCameraAndDependents = async (
element: HTMLElement,
hass: HomeAssistant,
cameraManager: CameraManager,
cardWideConfig: CardWideConfig,
view: View,
options?: {
targetView?: 'recording' | 'recordings';
},
): Promise<void> => {
const now = new Date();
const cameras = cameraManager.getCameras();
if (!cameras) {
return;
}
const cameraIDs = new Set(getAllDependentCameras(cameras, view.camera));
const queries = createQueriesForRecordingsView(
cameraManager,
cardWideConfig,
cameraIDs,
);
if (!queries) {
return;
}
(
await createViewForRecordings(element, hass, cameraManager, view, {
...options,
// Fetch 7 days worth of recordings (including recordings that are for the
// current hour).
start: sub(now, { days: 7 }),
end: add(now, { hours: 1 }),
await executeMediaQueryForView(element, hass, cameraManager, view, queries, {
targetView: options?.targetView,
})
)?.dispatchChangeEvent(element);
};
/**
* Create a view for recordings.
* @param element The element to dispatch the view change from.
* @param hass The Home Assistant object.
* @param cameraManager The datamanager to use for data access.
* @param cameras The camera configurations.
* @param view The current view.
* @param options A specific window (start and end) to fetch recordings for, a
* targetTime to seek to, a targetView to dispatch to and a set of cameraIDs to
* restrict to.
*/
export const createViewForRecordings = async (
element: HTMLElement,
hass: HomeAssistant,
export const createQueriesForRecordingsView = (
cameraManager: CameraManager,
view: View,
cardWideConfig: CardWideConfig,
cameraIDs: Set<string>,
options?: {
query?: RecordingMediaQueries;
cameraIDs?: Set<string>;
targetCameraID?: string;
targetView?: 'recording' | 'recordings';
targetTime?: Date;
start?: Date;
end?: Date;
},
): Promise<View | null> => {
const cameras = cameraManager.getCameras();
if (!cameras) {
return null;
}
const cameraIDs: Set<string> = options?.cameraIDs
? options.cameraIDs
: new Set(getAllDependentCameras(cameras, view.camera));
let query: RecordingMediaQueries;
if (options?.query) {
query = options.query;
} else {
const recordingQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, {
...(options?.start && { start: options.start }),
...(options?.end && { end: options.end }),
});
if (!recordingQueries) {
return null;
}
query = new RecordingMediaQueries(recordingQueries);
}
return executeMediaQueryForView(element, hass, cameraManager, view, query, {
cameraIDs: cameraIDs,
targetView: options?.targetView,
targetCameraID: options?.targetCameraID,
targetTime: options?.targetTime,
): RecordingMediaQueries | null => {
const limit =
cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT;
const recordingQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, {
limit: limit,
...(options?.start && { start: options.start }),
...(options?.end && { end: options.end }),
});
return recordingQueries ? new RecordingMediaQueries(recordingQueries) : null;
};
const executeMediaQueryForView = async (
export const executeMediaQueryForView = async (
element: HTMLElement,
hass: HomeAssistant,
cameraManager: CameraManager,
view: View,
query: MediaQueries,
options?: {
cameraIDs?: Set<string>;
targetCameraID?: string;
targetView?: FrigateCardView;
targetTime?: Date;
@@ -207,9 +160,9 @@ const executeMediaQueryForView = async (
const queryResults = new MediaQueriesResults(mediaArray, selectedIndex);
let viewerContext: ViewContext | undefined = {};
if (options?.targetTime && options.cameraIDs) {
if (options?.targetTime) {
queryResults.selectBestResult((media) =>
findClosestMediaIndex(media, options.targetTime as Date, options.cameraIDs),
findClosestMediaIndex(media, options.targetTime as Date),
);
viewerContext = {
mediaViewer: {
@@ -234,7 +187,6 @@ const executeMediaQueryForView = async (
* Find the closest matching media object.
* @param mediaArray The media. Must be sorted most recent first.
* @param targetTime The target time used to find the relevant child.
* @param cameraIDs The camera IDs to search for.
* @param refPoint Whether to find based on the start or end of the
* event/recording. If not specified, the first match is returned rather than
* the best match.
@@ -243,7 +195,6 @@ const executeMediaQueryForView = async (
export const findClosestMediaIndex = (
mediaArray: ViewMedia[],
targetTime: Date,
cameraIDs?: Set<string>,
refPoint?: 'start' | 'end',
): number | null => {
let bestMatch:
@@ -253,15 +204,7 @@ export const findClosestMediaIndex = (
}
| undefined;
if (!cameraIDs) {
return null;
}
for (const [i, media] of mediaArray.entries()) {
if (!cameraIDs.has(media.getCameraID())) {
continue;
}
if (media.includesTime(targetTime)) {
const start = media.getStartTime();
const end = media.getEndTime();