Remove the MediaQuery wrapper from the camera manager.

This commit is contained in:
Dermot Duffy
2023-01-29 20:00:45 -08:00
parent 767d4ee7a0
commit 01c3a79ff1
9 changed files with 69 additions and 69 deletions
+18 -34
View File
@@ -31,8 +31,6 @@ import {
import orderBy from 'lodash-es/orderBy'; import orderBy from 'lodash-es/orderBy';
import { CameraManagerEngineFactory } from './engine-factory.js'; import { CameraManagerEngineFactory } from './engine-factory.js';
import { ViewMedia } from '../view/media.js'; import { ViewMedia } from '../view/media.js';
import { MediaQueriesResults } from '../view/media-queries-results';
import { MediaQueries } from '../view/media-queries.js';
import uniqBy from 'lodash-es/uniqBy'; import uniqBy from 'lodash-es/uniqBy';
import { CameraManagerEngine } from './engine.js'; import { CameraManagerEngine } from './engine.js';
import sum from 'lodash-es/sum'; import sum from 'lodash-es/sum';
@@ -123,9 +121,7 @@ export class CameraManager {
}); });
} }
public async getMediaMetadata( public async getMediaMetadata(hass: HomeAssistant): Promise<MediaMetadata | null> {
hass: HomeAssistant,
): Promise<MediaMetadata | null> {
const what: Set<string> = new Set(); const what: Set<string> = new Set();
const where: Set<string> = new Set(); const where: Set<string> = new Set();
const days: Set<string> = new Set(); const days: Set<string> = new Set();
@@ -148,7 +144,7 @@ export class CameraManager {
engineMetadata.days.forEach(days.add, days); engineMetadata.days.forEach(days.add, days);
} }
} }
} };
await allPromises(engines, (engine) => processMetadata(engine)); await allPromises(engines, (engine) => processMetadata(engine));
@@ -159,7 +155,7 @@ export class CameraManager {
...(what.size && { what: what }), ...(what.size && { what: what }),
...(where.size && { where: where }), ...(where.size && { where: where }),
...(days.size && { days: days }), ...(days.size && { days: days }),
} };
} }
protected _generateDefaultQueries<PQT extends PartialDataQuery>( protected _generateDefaultQueries<PQT extends PartialDataQuery>(
@@ -228,25 +224,14 @@ export class CameraManager {
return await this._handleQuery(hass, query); return await this._handleQuery(hass, query);
} }
public async executeMediaQueries( public async executeMediaQueries<T extends MediaQuery>(
hass: HomeAssistant, hass: HomeAssistant,
mediaQueries: MediaQueries, queries: T[],
): Promise<MediaQueriesResults | null> { ): Promise<ViewMedia[] | null> {
const queries: (RecordingQuery | EventQuery)[] | null = mediaQueries.getQueries(); return this._convertQueryResultsToMedia(
if (!queries) {
return null;
}
const mediaArray = this._convertQueryResultsToMedia(
hass, hass,
await this._handleQuery(hass, queries), await this._handleQuery(hass, queries),
); );
return new MediaQueriesResults(
mediaArray,
// Select the first (most-recent) item.
mediaArray.length ? 0 : null,
);
} }
public async extendMediaQueries<T extends MediaQuery>( public async extendMediaQueries<T extends MediaQuery>(
@@ -328,9 +313,13 @@ export class CameraManager {
} }
return { return {
canFavoriteEvents: engines.some((engine) => engine.getCapabilities()?.canFavoriteEvents), canFavoriteEvents: engines.some(
canFavoriteRecordings: engines.some((engine) => engine.getCapabilities()?.canFavoriteRecordings), (engine) => engine.getCapabilities()?.canFavoriteEvents,
} ),
canFavoriteRecordings: engines.some(
(engine) => engine.getCapabilities()?.canFavoriteRecordings,
),
};
} }
public getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null { public getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null {
@@ -368,18 +357,13 @@ export class CameraManager {
} }
} }
public areMediaQueriesResultsFresh( public areMediaQueriesResultsFresh<T extends MediaQuery>(
queries: MediaQueries, queries: T[],
results: MediaQueriesResults, resultsTimestamp: Date,
): boolean { ): boolean {
const now = new Date(); const now = new Date();
const resultsTimestamp = results.getResultsTimestamp();
if (!resultsTimestamp) { for (const query of queries) {
return false;
}
for (const query of queries.getQueries() ?? []) {
const engines = this._engineFactory.getEnginesForCameraIDs( const engines = this._engineFactory.getEnginesForCameraIDs(
this._cameras, this._cameras,
query.cameraIDs, query.cameraIDs,
-1
View File
@@ -239,7 +239,6 @@ export class FrigateCardThumbnail extends LitElement {
@property({ attribute: false }) @property({ attribute: false })
public hass?: ExtendedHomeAssistant; public hass?: ExtendedHomeAssistant;
// CameraManager used for marking media as favorite.
@property({ attribute: false }) @property({ attribute: false })
public cameraManager?: CameraManager; public cameraManager?: CameraManager;
+13 -11
View File
@@ -59,6 +59,7 @@ import { ViewMedia } from '../view/media';
import { ViewMediaClassifier } from '../view/media-classifier'; import { ViewMediaClassifier } from '../view/media-classifier';
import { rangesOverlap } from '../camera-manager/range'; import { rangesOverlap } from '../camera-manager/range';
import { View } from '../view/view'; import { View } from '../view/view';
import { MediaQuery } from '../camera-manager/types';
interface FrigateCardGroupData { interface FrigateCardGroupData {
id: string; id: string;
@@ -501,11 +502,9 @@ export class FrigateCardTimelineCore extends LitElement {
targetTime: properties.time, targetTime: properties.time,
}, },
); );
} else if ( } else if (properties.item && properties.what === 'item') {
properties.item && const newResults = this.view.queryResults
properties.what === 'item' ?.clone()
) {
const newResults = this.view.queryResults?.clone()
.resetSelectedResult() .resetSelectedResult()
.selectResultIfFound( .selectResultIfFound(
(media) => !!this.cameras && media.getID() === properties.item, (media) => !!this.cameras && media.getID() === properties.item,
@@ -972,14 +971,17 @@ export class FrigateCardTimelineCore extends LitElement {
} }
protected _alreadyHasAcceptableMediaQuery(freshMediaQuery: MediaQueries): boolean { protected _alreadyHasAcceptableMediaQuery(freshMediaQuery: MediaQueries): boolean {
const currentQueries = this.view?.query?.getQueries();
const currentResultTimestamp = this.view?.queryResults?.getResultsTimestamp();
return ( return (
!!this.cameraManager && !!this.cameraManager &&
!!this.view?.query && !!currentQueries &&
!!this.view.queryResults && !!currentResultTimestamp &&
freshMediaQuery.isEqual(this.view.query) && isEqual(currentQueries, freshMediaQuery.getQueries()) &&
this.cameraManager.areMediaQueriesResultsFresh( this.cameraManager.areMediaQueriesResultsFresh<MediaQuery>(
this.view.query, currentQueries,
this.view.queryResults, currentResultTimestamp,
) )
); );
} }
+1
View File
@@ -42,6 +42,7 @@ export class FrigateCardTimeline extends LitElement {
.hass=${this.hass} .hass=${this.hass}
.view=${this.view} .view=${this.view}
.thumbnailConfig=${this.timelineConfig.controls.thumbnails} .thumbnailConfig=${this.timelineConfig.controls.thumbnails}
.cameraManager=${this.cameraManager}
.cameras=${this.cameras} .cameras=${this.cameras}
> >
<frigate-card-timeline-core <frigate-card-timeline-core
+9 -4
View File
@@ -380,18 +380,23 @@ export class FrigateCardViewerCarousel extends LitElement {
const clipQuery = this.view.query.clone(); const clipQuery = this.view.query.clone();
clipQuery.convertToClipsQueries(); clipQuery.convertToClipsQueries();
let results: MediaQueriesResults | null; const queries = clipQuery.getQueries();
if (!queries) {
return;
}
let mediaArray: ViewMedia[] | null;
try { try {
results = await this.cameraManager.executeMediaQueries(this.hass, clipQuery); mediaArray = await this.cameraManager.executeMediaQueries(this.hass, queries);
} catch (e) { } catch (e) {
errorToConsole(e as Error); errorToConsole(e as Error);
return; return;
} }
if (!mediaArray) {
if (!results) {
return; return;
} }
const results = new MediaQueriesResults(mediaArray);
results.selectResultIfFound((clipMedia) => clipMedia.getID() === media.getID()); results.selectResultIfFound((clipMedia) => clipMedia.getID() === media.getID());
if (!results.hasSelectedResult()) { if (!results.hasSelectedResult()) {
return; return;
+15 -4
View File
@@ -15,6 +15,7 @@ import { HomeAssistant } from 'custom-card-helpers';
import { dispatchFrigateCardErrorEvent } from '../components/message'; import { dispatchFrigateCardErrorEvent } from '../components/message';
import { MediaQueriesResults } from '../view/media-queries-results'; import { MediaQueriesResults } from '../view/media-queries-results';
import { errorToConsole } from './basic'; import { errorToConsole } from './basic';
import { MediaQuery } from '../camera-manager/types';
export const changeViewToRecentEventsForCameraAndDependents = async ( export const changeViewToRecentEventsForCameraAndDependents = async (
element: HTMLElement, element: HTMLElement,
@@ -179,19 +180,29 @@ const executeMediaQueryForView = async (
targetTime?: Date; targetTime?: Date;
}, },
): Promise<View | null> => { ): Promise<View | null> => {
let queryResults: MediaQueriesResults | null; let mediaArray: ViewMedia[] | null;
const queries = query.getQueries();
if (!queries) {
return null;
}
try { try {
queryResults = await cameraManager.executeMediaQueries(hass, query); mediaArray = await cameraManager.executeMediaQueries<MediaQuery>(hass, queries);
} catch (e) { } catch (e) {
errorToConsole(e as Error); errorToConsole(e as Error);
dispatchFrigateCardErrorEvent(element, e as Error); dispatchFrigateCardErrorEvent(element, e as Error);
return null; return null;
} }
if (!mediaArray) {
return null;
}
const queryResults = new MediaQueriesResults(mediaArray);
let viewerContext: ViewContext | undefined = {}; let viewerContext: ViewContext | undefined = {};
const mediaArray = queryResults?.getResults();
if (queryResults && mediaArray && options?.targetTime && options.cameraIDs) { if (options?.targetTime && options.cameraIDs) {
queryResults.selectBestResult((media) => queryResults.selectBestResult((media) =>
findClosestMediaIndex(media, options.targetTime as Date, options.cameraIDs), findClosestMediaIndex(media, options.targetTime as Date, options.cameraIDs),
); );
+12 -7
View File
@@ -7,9 +7,12 @@ import { ClipsOrSnapshotsOrAll, RecordingSegment } from '../types';
import { CameraManager } from '../camera-manager/manager'; import { CameraManager } from '../camera-manager/manager';
import { EventQuery } from '../camera-manager/types'; import { EventQuery } from '../camera-manager/types';
import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera-manager/util'; import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera-manager/util';
import { EventMediaQueries } from '../view/media-queries';
import { ViewMedia } from '../view/media'; import { ViewMedia } from '../view/media';
import { compressRanges, ExpiringMemoryRangeSet, MemoryRangeSet } from '../camera-manager/range'; import {
compressRanges,
ExpiringMemoryRangeSet,
MemoryRangeSet,
} from '../camera-manager/range';
import { errorToConsole, ModifyInterface } from './basic.js'; import { errorToConsole, ModifyInterface } from './basic.js';
// Allow timeline freshness to be at least this number of seconds out of date // Allow timeline freshness to be at least this number of seconds out of date
@@ -132,14 +135,13 @@ export class TimelineDataSource {
} }
const cacheFriendlyWindow = this.getCacheFriendlyEventWindow(window); const cacheFriendlyWindow = this.getCacheFriendlyEventWindow(window);
const eventQueries = this.getTimelineEventQueries(cacheFriendlyWindow) const eventQueries = this.getTimelineEventQueries(cacheFriendlyWindow);
if (!eventQueries) { if (!eventQueries) {
return; return;
} }
const query = new EventMediaQueries(eventQueries);
const results = await this._cameraManager.executeMediaQueries(hass, query); const mediaArray = await this._cameraManager.executeMediaQueries(hass, eventQueries);
for (const media of results?.getResults() ?? []) { for (const media of mediaArray ?? []) {
const endTime = media.getEndTime(); const endTime = media.getEndTime();
const startTime = media.getStartTime(); const startTime = media.getStartTime();
const id = media.getID(); const id = media.getID();
@@ -234,7 +236,10 @@ export class TimelineDataSource {
if (!recordingQueries) { if (!recordingQueries) {
return; return;
} }
const results = await this._cameraManager.getRecordingSegments(hass, recordingQueries); const results = await this._cameraManager.getRecordingSegments(
hass,
recordingQueries,
);
const newSegments: Map<string, RecordingSegment[]> = new Map(); const newSegments: Map<string, RecordingSegment[]> = new Map();
for (const [query, result] of results) { for (const [query, result] of results) {
+1 -3
View File
@@ -10,9 +10,7 @@ export class MediaQueriesResults {
if (results) { if (results) {
this.setResults(results); this.setResults(results);
} }
if (selectedIndex !== undefined) { this.selectResult(selectedIndex ?? 0);
this.selectResult(selectedIndex);
}
} }
public clone(): MediaQueriesResults { public clone(): MediaQueriesResults {
-5
View File
@@ -1,4 +1,3 @@
import isEqual from 'lodash-es/isEqual';
import cloneDeep from 'lodash-es/cloneDeep.js'; import cloneDeep from 'lodash-es/cloneDeep.js';
import { EventQuery, MediaQuery, RecordingQuery } from '../camera-manager/types.js'; import { EventQuery, MediaQuery, RecordingQuery } from '../camera-manager/types.js';
@@ -17,10 +16,6 @@ export class MediaQueriesBase<T extends MediaQuery> {
return cloneDeep(this); return cloneDeep(this);
} }
public isEqual(that: MediaQueries): boolean {
return isEqual(this.getQueries(), that.getQueries());
}
public getQueries(): T[] | null { public getQueries(): T[] | null {
return this._queries; return this._queries;
} }