diff --git a/src/utils/data/data-manager-cache.ts b/src/camera/cache.ts similarity index 92% rename from src/utils/data/data-manager-cache.ts rename to src/camera/cache.ts index ad6ee7d1..f7bf53f0 100644 --- a/src/utils/data/data-manager-cache.ts +++ b/src/camera/cache.ts @@ -1,9 +1,9 @@ import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; import sortedUniqBy from 'lodash-es/sortedUniqBy'; -import { RecordingSegment, RecordingSegments } from '../frigate'; -import { DateRange, MemoryRangeSet } from './data-manager-range'; -import { DataQuery, QueryResults } from './data-types'; +import { RecordingSegment, RecordingSegments } from '../utils/frigate'; +import { DateRange, MemoryRangeSet } from './range'; +import { DataQuery, QueryResults } from './types'; interface RequestCacheItem { request: Request; @@ -11,14 +11,14 @@ interface RequestCacheItem { expires?: Date; } -interface DataManagerCache { +interface CameraManagerCache { get(request: Request): Response | null; has(request: Request): boolean; set(request: Request, response: Response, expiry?: Date): void; } export class MemoryRequestCache - implements DataManagerCache + implements CameraManagerCache { protected _data: RequestCacheItem[] = []; diff --git a/src/camera/engine-factory.ts b/src/camera/engine-factory.ts new file mode 100644 index 00000000..7e36b18d --- /dev/null +++ b/src/camera/engine-factory.ts @@ -0,0 +1,42 @@ +import { CameraConfig } from '../types'; +import { RecordingSegmentsCache } from './cache'; +import { CameraManagerEngine } from './engine'; +import { FrigateCameraManagerEngine } from './engine-frigate'; +import { DataQuery } from './types'; + +export class CameraManagerEngineFactory { + protected _engines: Map = new Map(); + + protected _getOrCreateEngine(engineKey: string): CameraManagerEngine | null { + const cachedEngine = this._engines.get(engineKey); + if (cachedEngine) { + return cachedEngine; + } + let newEngine: CameraManagerEngine | null = null; + switch (engineKey) { + case 'frigate': + newEngine = new FrigateCameraManagerEngine(new RecordingSegmentsCache()); + break; + } + if (newEngine) { + this._engines.set(engineKey, newEngine); + } + return newEngine; + } + + public getEngineForQuery( + cameras: Map, + query: DataQuery, + ): CameraManagerEngine | null { + const cameraConfig = cameras.get(query.cameraID); + return cameraConfig ? this.getEngineForCamera(cameraConfig) : null; + } + + public getEngineForCamera(cameraConfig: CameraConfig): CameraManagerEngine | null { + let engineKey: string | null = null; + if (cameraConfig.frigate.camera_name) { + engineKey = 'frigate'; + } + return engineKey ? this._getOrCreateEngine(engineKey) : null; + } +} diff --git a/src/utils/data/data-manager-engine-frigate.ts b/src/camera/engine-frigate.ts similarity index 92% rename from src/utils/data/data-manager-engine-frigate.ts rename to src/camera/engine-frigate.ts index 4ed00aed..5b82adb1 100644 --- a/src/utils/data/data-manager-engine-frigate.ts +++ b/src/camera/engine-frigate.ts @@ -3,11 +3,11 @@ import add from 'date-fns/add'; import endOfHour from 'date-fns/endOfHour'; import getUnixTime from 'date-fns/getUnixTime'; import startOfHour from 'date-fns/startOfHour'; -import { CAMERA_BIRDSEYE } from '../../const'; -import { CameraConfig, FrigateRecording } from '../../types'; -import { MediaQueries, MediaQueriesResults } from '../../view'; -import { ViewMedia, ViewMediaClassifier, ViewMediaFactory } from '../../view-media'; -import { errorToConsole } from '../basic'; +import { CAMERA_BIRDSEYE } from '../const'; +import { CameraConfig, FrigateRecording } from '../types'; +import { MediaQueries, MediaQueriesResults } from '../view'; +import { ViewMedia, ViewMediaClassifier, ViewMediaFactory } from '../view-media'; +import { errorToConsole } from '../utils/basic'; import { getEvents, getRecordingSegments, @@ -17,14 +17,14 @@ import { RecordingSegments, RecordingSummary, retainEvent, -} from '../frigate'; -import { RecordingSegmentsCache } from './data-manager-cache'; +} from '../utils/frigate'; +import { RecordingSegmentsCache } from './cache'; import { - DataManagerEngine, - DATA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, -} from './data-manager-engine'; -import { DataManagerError } from './data-manager-error'; -import { DateRange } from './data-manager-range'; + CameraManagerEngine, + CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, +} from './engine'; +import { CameraManagerError } from './error'; +import { DateRange } from './range'; import { Engine, EventQuery, @@ -40,7 +40,7 @@ import { QueryType, RecordingQuery, RecordingSegmentsQuery, -} from './data-types'; +} from './types'; const EVENT_REQUEST_CACHE_MAX_AGE_SECONDS = 60; const RECORDING_SUMMARY_REQUEST_CACHE_MAX_AGE_SECONDS = 60; @@ -70,7 +70,7 @@ class FrigateQueryResultsClassifier { } } -export class FrigateDataManagerEngine implements DataManagerEngine { +export class FrigateCameraManagerEngine implements CameraManagerEngine { protected _recordingSegmentsCache: RecordingSegmentsCache; constructor(recordingSegmentsCache: RecordingSegmentsCache) { @@ -157,7 +157,7 @@ export class FrigateDataManagerEngine implements DataManagerEngine { await retainEvent(hass, clientID, media.getID(cameraConfig), favorite); } catch (e) { errorToConsole(e as Error); - throw new DataManagerError((e as Error).message); + throw new CameraManagerError((e as Error).message); } media.setFavorite(favorite); @@ -183,7 +183,7 @@ export class FrigateDataManagerEngine implements DataManagerEngine { ...(query?.limit && { limit: query.limit }), ...(query?.hasClip && { has_clip: query.hasClip }), ...(query?.hasSnapshot && { has_snapshot: query.hasSnapshot }), - limit: query?.limit ?? DATA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, + limit: query?.limit ?? CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, }; try { @@ -196,7 +196,7 @@ export class FrigateDataManagerEngine implements DataManagerEngine { return result; } catch (e) { errorToConsole(e as Error); - throw new DataManagerError((e as Error).message, query); + throw new CameraManagerError((e as Error).message, query); } } @@ -222,7 +222,7 @@ export class FrigateDataManagerEngine implements DataManagerEngine { ); } catch (e) { errorToConsole(e as Error); - throw new DataManagerError((e as Error).message, query); + throw new CameraManagerError((e as Error).message, query); } const recordings: FrigateRecording[] = []; @@ -295,7 +295,7 @@ export class FrigateDataManagerEngine implements DataManagerEngine { segments = await getRecordingSegments(hass, request); } catch (e) { errorToConsole(e as Error); - throw new DataManagerError((e as Error).message, query); + throw new CameraManagerError((e as Error).message, query); } this._recordingSegmentsCache.add(query.cameraID, range, segments); diff --git a/src/utils/data/data-manager-engine.ts b/src/camera/engine.ts similarity index 86% rename from src/utils/data/data-manager-engine.ts rename to src/camera/engine.ts index 171a2785..f1c27aae 100644 --- a/src/utils/data/data-manager-engine.ts +++ b/src/camera/engine.ts @@ -1,7 +1,7 @@ import { HomeAssistant } from 'custom-card-helpers'; -import { CameraConfig } from '../../types'; -import { MediaQueries, MediaQueriesResults } from '../../view'; -import { ViewMedia } from '../../view-media'; +import { CameraConfig } from '../types'; +import { MediaQueries, MediaQueriesResults } from '../view'; +import { ViewMedia } from '../view-media'; import { EventQuery, PartialEventQuery, @@ -10,11 +10,11 @@ import { QueryReturnType, RecordingQuery, RecordingSegmentsQuery, -} from './data-types'; +} from './types'; -export const DATA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000; +export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000; -export interface DataManagerEngine { +export interface CameraManagerEngine { generateDefaultEventQuery( cameraID: string, cameraConfig: CameraConfig, diff --git a/src/camera/error.ts b/src/camera/error.ts new file mode 100644 index 00000000..b131e5c3 --- /dev/null +++ b/src/camera/error.ts @@ -0,0 +1,3 @@ +import { FrigateCardError } from '../types'; + +export class CameraManagerError extends FrigateCardError {} diff --git a/src/utils/data/data-manager.ts b/src/camera/manager.ts similarity index 94% rename from src/utils/data/data-manager.ts rename to src/camera/manager.ts index 75ab4a27..7c79c31b 100644 --- a/src/utils/data/data-manager.ts +++ b/src/camera/manager.ts @@ -1,6 +1,6 @@ import { HomeAssistant } from 'custom-card-helpers'; -import { CameraConfig } from '../../types.js'; -import { arrayify, setify } from '../basic.js'; +import { CameraConfig } from '../types.js'; +import { arrayify, setify } from '../utils/basic.js'; import { DataQuery, EventQuery, @@ -18,12 +18,12 @@ import { RecordingQueryResults, RecordingSegmentsQuery, RecordingSegmentsQueryResults, -} from './data-types.js'; +} from './types.js'; import orderBy from 'lodash-es/orderBy'; -import { DataManagerEngineFactory } from './data-manager-engine-factory.js'; -import { ViewMedia } from '../../view-media.js'; -import { MediaQueries, MediaQueriesResults } from '../../view.js'; -import { MemoryRequestCache } from './data-manager-cache.js'; +import { CameraManagerEngineFactory } from './engine-factory.js'; +import { ViewMedia } from '../view-media.js'; +import { MediaQueries, MediaQueriesResults } from '../view.js'; +import { MemoryRequestCache } from './cache.js'; export class QueryClassifier { public static isEventQuery(query: DataQuery | PartialDataQuery): query is EventQuery { @@ -61,13 +61,13 @@ export class QueryResultClassifier { export type RequestCache = MemoryRequestCache; -export class DataManager { - protected _engineFactory: DataManagerEngineFactory; +export class CameraManager { + protected _engineFactory: CameraManagerEngineFactory; protected _cameras: Map; protected _requestCache: RequestCache; constructor( - engineFactory: DataManagerEngineFactory, + engineFactory: CameraManagerEngineFactory, cameras: Map, requestCache: RequestCache, ) { @@ -296,7 +296,7 @@ export class DataManager { await Promise.all(_queries.map((query) => processQuery(query))); console.debug( - 'Frigate Card DataManager request (Cached:', + 'Frigate Card CameraManager request (Cached:', `${queryCachedCount}/${_queries.length},`, `Duration: ${(new Date().getTime() - queryStartTime.getTime()) / 1000}s,`, 'Queries:', diff --git a/src/utils/data/data-manager-range.ts b/src/camera/range.ts similarity index 100% rename from src/utils/data/data-manager-range.ts rename to src/camera/range.ts diff --git a/src/utils/data/data-types.ts b/src/camera/types.ts similarity index 96% rename from src/utils/data/data-types.ts rename to src/camera/types.ts index afafa4d9..bdb63985 100644 --- a/src/utils/data/data-types.ts +++ b/src/camera/types.ts @@ -1,5 +1,5 @@ -import { FrigateEvents, FrigateRecording } from '../../types'; -import { RecordingSegments } from '../frigate'; +import { FrigateEvents, FrigateRecording } from '../types'; +import { RecordingSegments } from '../utils/frigate'; // ==== // Base diff --git a/src/utils/data/data-manager-util.ts b/src/camera/util.ts similarity index 96% rename from src/utils/data/data-manager-util.ts rename to src/camera/util.ts index 5a56741b..9b09ef95 100644 --- a/src/utils/data/data-manager-util.ts +++ b/src/camera/util.ts @@ -5,7 +5,7 @@ import endOfDay from 'date-fns/endOfDay'; import endOfMinute from 'date-fns/endOfMinute'; import endOfWeek from 'date-fns/endOfWeek'; import startOfWeek from 'date-fns/startOfWeek'; -import { DateRange } from './data-manager-range'; +import { DateRange } from './range'; export const convertRangeToCacheFriendlyTimes = ( range: DateRange, diff --git a/src/card.ts b/src/card.ts index 86322916..4ead268e 100644 --- a/src/card.ts +++ b/src/card.ts @@ -91,10 +91,10 @@ import { isValidMediaLoadedInfo } from './utils/media-info.js'; import { View } from './view.js'; import pkg from '../package.json'; import { ViewContext } from 'view'; -import { DataManager } from './utils/data/data-manager.js'; +import { CameraManager } from './camera/manager.js'; import { setLowPerformanceProfile, setPerformanceCSSStyles } from './performance.js'; -import { DataManagerEngineFactory } from './utils/data/data-manager-engine-factory.js'; -import { RequestCache } from './utils/data/data-manager-cache.js'; +import { CameraManagerEngineFactory } from './camera/engine-factory.js'; +import { RequestCache } from './camera/cache.js'; /** A note on media callbacks: * @@ -205,7 +205,7 @@ export class FrigateCard extends LitElement { // A cache of resolved media URLs/mimetypes for use in the whole card. protected _resolvedMediaCache = new ResolvedMediaCache(); - protected _dataManager?: DataManager; + protected _cameraManager?: CameraManager; // The mouse handler may be called continually, throttle it to at most once // per second for performance reasons. @@ -1101,8 +1101,8 @@ export class FrigateCard extends LitElement { */ protected willUpdate(changedProps: PropertyValues): void { if (this._cameras && (changedProps.has('_config') || changedProps.has('_cameras'))) { - this._dataManager = new DataManager( - new DataManagerEngineFactory(), + this._cameraManager = new CameraManager( + new CameraManagerEngineFactory(), this._cameras, new RequestCache(), ); @@ -1336,7 +1336,7 @@ export class FrigateCard extends LitElement { return; } - const path = this._dataManager?.getMediaDownloadPath(media); + const path = this._cameraManager?.getMediaDownloadPath(media); if (!path) { return; } @@ -2018,7 +2018,7 @@ export class FrigateCard extends LitElement { .view=${this._view} .cameras=${this._cameras} .galleryConfig=${this._getConfig().event_gallery} - .dataManager=${this._dataManager} + .cameraManager=${this._cameraManager} .cardWideConfig=${this._cardWideConfig} > ` @@ -2030,7 +2030,7 @@ export class FrigateCard extends LitElement { .cameras=${this._cameras} .viewerConfig=${this._getConfig().media_viewer} .resolvedMediaCache=${this._resolvedMediaCache} - .dataManager=${this._dataManager} + .cameraManager=${this._cameraManager} .cardWideConfig=${this._cardWideConfig} > ` @@ -2041,7 +2041,7 @@ export class FrigateCard extends LitElement { .view=${this._view} .cameras=${this._cameras} .timelineConfig=${this._getConfig().timeline} - .dataManager=${this._dataManager} + .cameraManager=${this._cameraManager} > ` : ``} @@ -2062,7 +2062,7 @@ export class FrigateCard extends LitElement { .conditionState=${this._conditionState} .liveOverrides=${getOverridesByKey(this._getConfig().overrides, 'live')} .cameras=${this._cameras} - .dataManager=${this._dataManager} + .cameraManager=${this._cameraManager} .cardWideConfig=${this._cardWideConfig} class="${classMap(liveClasses)}" > diff --git a/src/components/gallery.ts b/src/components/gallery.ts index f0b72ad3..46658f46 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -22,7 +22,7 @@ import { getFullDependentBrowseMediaQueryParametersOrDispatchError, } from '../utils/ha/browse-media'; import { changeViewToRecentEventsForCameraAndDependents, changeViewToRecentRecordingForCameraAndDependents } from '../utils/media-to-view.js'; -import { DataManager } from '../utils/data/data-manager.js'; +import { CameraManager } from '../camera/manager.js'; import { View } from '../view.js'; import { renderProgressIndicator } from './message.js'; import './thumbnail.js'; @@ -54,7 +54,7 @@ export class FrigateCardGallery extends LitElement { public cameras?: Map; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; @property({ attribute: false }) public cardWideConfig?: CardWideConfig; @@ -71,7 +71,7 @@ export class FrigateCardGallery extends LitElement { // !this.cameras || // !this.view.isGalleryView() || // !mediaType || - // !this.dataManager + // !this.cameraManager // ) { // return; // } @@ -81,7 +81,7 @@ export class FrigateCardGallery extends LitElement { // changeViewToRecentRecordingForCameraAndDependents( // this, // this.hass, - // this.dataManager, + // this.cameraManager, // this.cameras, // this.view, // { @@ -92,7 +92,7 @@ export class FrigateCardGallery extends LitElement { // changeViewToRecentEventsForCameraAndDependents( // this, // this.hass, - // this.dataManager, + // this.cameraManager, // this.cameras, // this.view, // { diff --git a/src/components/live/live.ts b/src/components/live/live.ts index e53f8685..d1c609f7 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -51,7 +51,7 @@ import '../surround.js'; import { EmblaCarouselPlugins } from '../carousel.js'; import { classMap } from 'lit/directives/class-map.js'; import { updateElementStyleFromMediaLayoutConfig } from '../../utils/media-layout.js'; -import { DataManager } from '../../utils/data/data-manager.js'; +import { CameraManager } from '../../camera/manager.js'; import { HomeAssistant } from 'custom-card-helpers'; import { dispatchMessageEvent, dispatchErrorMessageEvent } from '../message.js'; import { HassEntity } from 'home-assistant-js-websocket'; @@ -115,7 +115,7 @@ export class FrigateCardLive extends LitElement { public liveOverrides?: LiveOverrides; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; @property({ attribute: false }) public cardWideConfig?: CardWideConfig; @@ -231,7 +231,7 @@ export class FrigateCardLive extends LitElement { .thumbnailConfig=${config.controls.thumbnails} .timelineConfig=${config.controls.timeline} .cameras=${this.cameras} - .dataManager=${this.dataManager} + .cameraManager=${this.cameraManager} .inBackground=${this._inBackground} @frigate-card:message=${(ev: CustomEvent) => { this._renderKey++; diff --git a/src/components/surround.ts b/src/components/surround.ts index d46754ca..460dbabe 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -16,7 +16,7 @@ import { ThumbnailsControlConfig, } from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { DataManager } from '../utils/data/data-manager.js'; +import { CameraManager } from '../camera/manager.js'; import { View } from '../view.js'; import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; import './surround-basic.js'; @@ -58,7 +58,7 @@ export class FrigateCardSurround extends LitElement { public cameras?: Map; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; /** * Fetch thumbnail media when a target is not specified in the view (e.g. for @@ -69,7 +69,7 @@ export class FrigateCardSurround extends LitElement { protected async _fetchMedia(): Promise { if ( !this.cameras || - !this.dataManager || + !this.cameraManager || !this.fetchMedia || this.inBackground || !this.hass || @@ -84,7 +84,7 @@ export class FrigateCardSurround extends LitElement { await changeViewToRecentEventsForCameraAndDependents( this, this.hass, - this.dataManager, + this.cameraManager, this.cameras, this.view, { @@ -156,7 +156,7 @@ export class FrigateCardSurround extends LitElement { slot=${this.thumbnailConfig.mode} .hass=${this.hass} .config=${this.thumbnailConfig} - .dataManager=${this.dataManager} + .cameraManager=${this.cameraManager} .view=${this.view} .cameras=${this.cameras} .selected=${this.view.queryResults?.getSelectedIndex() ?? undefined} @@ -194,7 +194,7 @@ export class FrigateCardSurround extends LitElement { .timelineConfig=${this.timelineConfig} .thumbnailDetails=${this.thumbnailConfig?.show_details} .thumbnailSize=${this.thumbnailConfig?.size} - .dataManager=${this.dataManager} + .cameraManager=${this.cameraManager} > ` : ''} diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 82b4fa1e..d4e3becd 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -24,7 +24,7 @@ import { FrigateCardCarousel } from './carousel.js'; import './thumbnail.js'; import './carousel.js'; import { ifDefined } from 'lit/directives/if-defined.js'; -import { DataManager } from '../utils/data/data-manager.js'; +import { CameraManager } from '../camera/manager.js'; export interface ThumbnailCarouselTap { queryResults: MediaQueriesResults; @@ -42,7 +42,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { public cameras?: Map; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; protected _refCarousel: Ref = createRef(); @@ -161,7 +161,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { return html` { stopEventFromActivatingCardWideActions(ev); if (this.hass && this.cameraConfig && this.media) { - this.dataManager?.favoriteMedia( + this.cameraManager?.favoriteMedia( this.hass, this.cameraConfig, this.media, diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 1bee6125..28be5db1 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -49,13 +49,13 @@ import { createViewForRecordings, generateMediaViewerContext, } from '../utils/media-to-view'; -import { DataManager } from '../utils/data/data-manager'; +import { CameraManager } from '../camera/manager'; import { EventMediaQueries, MediaQueries, View } from '../view'; import { dispatchMessageEvent } from './message.js'; import './thumbnail.js'; import { FrigateCardTimelineItem, TimelineDataSource } from '../utils/timeline-source'; import { ViewMedia, ViewMediaClassifier } from '../view-media'; -import { rangesOverlap } from '../utils/data/data-manager-range'; +import { rangesOverlap } from '../camera/range'; interface FrigateCardGroupData { id: string; @@ -89,7 +89,7 @@ declare module 'view' { interface ThumbnailDataRequest { item: IdType; hass?: ExtendedHomeAssistant; - dataManager?: DataManager; + cameraManager?: CameraManager; cameraConfig?: CameraConfig; media?: ViewMedia; view?: View; @@ -142,7 +142,7 @@ export class FrigateCardTimelineThumbnail extends LitElement { if ( !dataRequest.hass || - !dataRequest.dataManager || + !dataRequest.cameraManager || !dataRequest.cameraConfig || !dataRequest.media || !dataRequest.view @@ -152,7 +152,7 @@ export class FrigateCardTimelineThumbnail extends LitElement { return html` => { - if (!properties.item || !this.dataManager || !this.hass) { + if (!properties.item || !this.cameraManager || !this.hass) { return null; } const view = await this._createViewWithEventMediaQuery( @@ -518,7 +518,7 @@ export class FrigateCardTimelineCore extends LitElement { view.mergeInContext( await generateMediaViewerContext( this.hass, - this.dataManager, + this.cameraManager, results, properties.time, ), @@ -645,12 +645,12 @@ export class FrigateCardTimelineCore extends LitElement { noSetWindow?: boolean; }, ): Promise { - if (!this.hass || !this.dataManager || !this.cameras || !this.view || !query) { + if (!this.hass || !this.cameraManager || !this.cameras || !this.view || !query) { return null; } const view = await createViewForEvents( this.hass, - this.dataManager, + this.cameraManager, this.cameras, this.view, { @@ -983,11 +983,11 @@ export class FrigateCardTimelineCore extends LitElement { protected _alreadyHasAcceptableMediaQuery(freshMediaQuery: MediaQueries): boolean { return ( - !!this.dataManager && + !!this.cameraManager && !!this.view?.query && !!this.view.queryResults && freshMediaQuery.isEqual(this.view.query) && - this.dataManager.areMediaQueriesResultsFresh( + this.cameraManager.areMediaQueriesResultsFresh( this.view.query, this.view.queryResults, ) @@ -1033,13 +1033,13 @@ export class FrigateCardTimelineCore extends LitElement { } if ( - changedProps.has('dataManager') || + changedProps.has('cameraManager') || changedProps.has('cameras') || changedProps.has('timelineConfig') ) { - if (this.dataManager && this.cameras && this.timelineConfig) { + if (this.cameraManager && this.cameras && this.timelineConfig) { this._timelineSource = new TimelineDataSource( - this.dataManager, + this.cameraManager, this._getTimelineCameraIDs(), this.timelineConfig.media, ); @@ -1069,7 +1069,7 @@ export class FrigateCardTimelineCore extends LitElement { protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); - if (changedProperties.has('cameras') || changedProperties.has('dataManager')) { + if (changedProperties.has('cameras') || changedProperties.has('cameraManager')) { this._destroy(); } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index 44766235..064a70fe 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -2,7 +2,7 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit import { customElement, property } from 'lit/decorators.js'; import timelineStyle from '../scss/timeline.scss'; import { CameraConfig, ExtendedHomeAssistant, TimelineConfig } from '../types'; -import { DataManager } from '../utils/data/data-manager'; +import { CameraManager } from '../camera/manager'; import { View } from '../view'; import './surround.js'; import './timeline-core.js'; @@ -27,7 +27,7 @@ export class FrigateCardTimeline extends LitElement { public timelineConfig?: TimelineConfig; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; /** * Master render method. @@ -51,7 +51,7 @@ export class FrigateCardTimeline extends LitElement { .timelineConfig=${this.timelineConfig} .thumbnailDetails=${this.timelineConfig.controls.thumbnails.show_details} .thumbnailSize=${this.timelineConfig.controls.thumbnails.size} - .dataManager=${this.dataManager} + .cameraManager=${this.cameraManager} > `; diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 87793467..503fcd84 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -46,7 +46,7 @@ import '../patches/ha-hls-player'; import './surround.js'; import { renderTask } from '../utils/task.js'; import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout.js'; -import { DataManager } from '../utils/data/data-manager.js'; +import { CameraManager } from '../camera/manager.js'; import { changeViewToRecentEventsForCameraAndDependents, changeViewToRecentRecordingForCameraAndDependents, @@ -92,7 +92,7 @@ export class FrigateCardViewer extends LitElement { public resolvedMediaCache?: ResolvedMediaCache; @property({ attribute: false }) - public dataManager?: DataManager; + public cameraManager?: CameraManager; @property({ attribute: false }) public cardWideConfig?: CardWideConfig; @@ -107,7 +107,7 @@ export class FrigateCardViewer extends LitElement { !this.view || !this.cameras || !this.viewerConfig || - !this.dataManager + !this.cameraManager ) { return; } @@ -134,7 +134,7 @@ export class FrigateCardViewer extends LitElement { changeViewToRecentRecordingForCameraAndDependents( this, this.hass, - this.dataManager, + this.cameraManager, this.cameras, this.view, { @@ -145,7 +145,7 @@ export class FrigateCardViewer extends LitElement { changeViewToRecentEventsForCameraAndDependents( this, this.hass, - this.dataManager, + this.cameraManager, this.cameras, this.view, { @@ -161,7 +161,7 @@ export class FrigateCardViewer extends LitElement { .view=${this.view} .thumbnailConfig=${this.viewerConfig.controls.thumbnails} .timelineConfig=${this.viewerConfig.controls.timeline} - .dataManager=${this.dataManager} + .cameraManager=${this.cameraManager} .cameras=${this.cameras} > = new Map(); - - protected _getOrCreateEngine(engineKey: string): DataManagerEngine | null { - const cachedEngine = this._engines.get(engineKey); - if (cachedEngine) { - return cachedEngine; - } - let newEngine: DataManagerEngine | null = null; - switch (engineKey) { - case 'frigate': - newEngine = new FrigateDataManagerEngine(new RecordingSegmentsCache()); - break; - } - if (newEngine) { - this._engines.set(engineKey, newEngine); - } - return newEngine; - } - - public getEngineForQuery( - cameras: Map, - query: DataQuery, - ): DataManagerEngine | null { - const cameraConfig = cameras.get(query.cameraID); - return cameraConfig ? this.getEngineForCamera(cameraConfig) : null; - } - - public getEngineForCamera(cameraConfig: CameraConfig): DataManagerEngine | null { - let engineKey: string | null = null; - if (cameraConfig.frigate.camera_name) { - engineKey = 'frigate'; - } - return engineKey ? this._getOrCreateEngine(engineKey) : null; - } -} diff --git a/src/utils/data/data-manager-error.ts b/src/utils/data/data-manager-error.ts deleted file mode 100644 index ccd19902..00000000 --- a/src/utils/data/data-manager-error.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { FrigateCardError } from '../../types'; - -export class DataManagerError extends FrigateCardError {} diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index eec0346b..dfa4640e 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -6,7 +6,7 @@ import { ViewContext } from 'view'; import { CameraConfig, ClipsOrSnapshotsOrAll, FrigateCardView } from '../types'; import { EventMediaQueries, RecordingMediaQueries, View } from '../view'; import { RecordingSegments } from './frigate'; -import { DataManager } from './data/data-manager'; +import { CameraManager } from '../camera/manager'; import { getAllDependentCameras } from './camera.js'; import { ViewMedia, ViewMediaClassifier } from '../view-media'; import { HomeAssistant } from 'custom-card-helpers'; @@ -14,7 +14,7 @@ import { HomeAssistant } from 'custom-card-helpers'; export const changeViewToRecentEventsForCameraAndDependents = async ( element: HTMLElement, hass: HomeAssistant, - dataManager: DataManager, + cameraManager: CameraManager, cameras: Map, view: View, options?: { @@ -23,7 +23,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( }, ): Promise => { ( - await createViewForEvents(hass, dataManager, cameras, view, { + await createViewForEvents(hass, cameraManager, cameras, view, { ...options, limit: 50, // Capture the 50 most recent events. }) @@ -32,7 +32,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( export const createViewForEvents = async ( hass: HomeAssistant, - dataManager: DataManager, + cameraManager: CameraManager, cameras: Map, view: View, options?: { @@ -51,7 +51,7 @@ export const createViewForEvents = async ( ? options.cameraIDs : new Set(getAllDependentCameras(cameras, view.camera)); - const queries = dataManager.generateDefaultEventQueries(cameraIDs, { + const queries = cameraManager.generateDefaultEventQueries(cameraIDs, { ...(options?.limit && { limit: options.limit }), ...((!options?.mediaType || ['clips', 'all'].includes(options.mediaType)) && { hasClip: true, @@ -60,7 +60,7 @@ export const createViewForEvents = async ( }); query = new EventMediaQueries(queries); } - const queryResults = await dataManager.executeMediaQuery(hass, query); + const queryResults = await cameraManager.executeMediaQuery(hass, query); return view?.evolve({ view: options?.targetView, @@ -73,7 +73,7 @@ export const createViewForEvents = async ( * Change the view to a recent recording. * @param element The element to dispatch the view change from. * @param hass The Home Assistant object. - * @param dataManager The datamanager to use for data access. + * @param cameraManager The datamanager to use for data access. * @param cameras The camera configurations. * @param view The current view. * @param options A set of cameraIDs to fetch recordings for, and a targetView to dispatch to. @@ -81,7 +81,7 @@ export const createViewForEvents = async ( export const changeViewToRecentRecordingForCameraAndDependents = async ( element: HTMLElement, hass: HomeAssistant, - dataManager: DataManager, + cameraManager: CameraManager, cameras: Map, view: View, options?: { @@ -90,7 +90,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( ): Promise => { const now = new Date(); ( - await createViewForRecordings(hass, dataManager, cameras, view, { + await createViewForRecordings(hass, cameraManager, cameras, view, { ...options, // Fetch 7 days worth of recordings (including recordings that are for the // current hour). @@ -103,7 +103,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( /** * Create a view for recordings. * @param hass The Home Assistant object. - * @param dataManager The datamanager to use for data access. + * @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 @@ -112,7 +112,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( */ export const createViewForRecordings = async ( hass: HomeAssistant, - dataManager: DataManager, + cameraManager: CameraManager, cameras: Map, view: View, options?: { @@ -127,13 +127,13 @@ export const createViewForRecordings = async ( ? options.cameraIDs : new Set(getAllDependentCameras(cameras, view.camera)); - const queries = dataManager.generateDefaultRecordingQueries(cameraIDs, { + const queries = cameraManager.generateDefaultRecordingQueries(cameraIDs, { ...(options?.start && { start: options.start }), ...(options?.end && { end: options.end }), }); const query = new RecordingMediaQueries(queries); - const queryResults = await dataManager.executeMediaQuery(hass, query); + const queryResults = await cameraManager.executeMediaQuery(hass, query); let viewerContext: ViewContext | undefined = {}; const mediaArray = queryResults?.getResults(); @@ -143,7 +143,7 @@ export const createViewForRecordings = async ( ); viewerContext = await generateMediaViewerContext( hass, - dataManager, + cameraManager, mediaArray, options.targetTime, ); @@ -164,14 +164,14 @@ export const createViewForRecordings = async ( * Generate the media view context for a set of media children (used to set * seek times into each media item). * @param hass The Home Assistant object. - * @param dataManager The datamanager to use for data access. + * @param cameraManager The datamanager to use for data access. * @param media The media. * @param targetTime The target time. * @returns The ViewContext. */ export const generateMediaViewerContext = async ( hass: HomeAssistant, - dataManager: DataManager, + cameraManager: CameraManager, media: ViewMedia[], targetTime: Date, ): Promise => { @@ -188,14 +188,14 @@ export const generateMediaViewerContext = async ( let seekSeconds: number | null = null; if (targetTime >= start && targetTime <= end) { - const query = dataManager.generateDefaultRecordingSegmentsQueries( + const query = cameraManager.generateDefaultRecordingSegmentsQueries( child.getCameraID(), { start: start, end: end, }, )[0]; - const segments = (await dataManager.getRecordingSegments(hass, query)).get(query); + const segments = (await cameraManager.getRecordingSegments(hass, query)).get(query); if (segments) { seekSeconds = getSeekTimeInSegments( diff --git a/src/utils/timeline-source.ts b/src/utils/timeline-source.ts index badfbf30..3ddc9a94 100644 --- a/src/utils/timeline-source.ts +++ b/src/utils/timeline-source.ts @@ -4,17 +4,13 @@ import sub from 'date-fns/sub'; import { DataSet } from 'vis-data'; import { IdType, TimelineItem, TimelineWindow } from 'vis-timeline/esnext'; import { CameraConfig, ClipsOrSnapshotsOrAll } from '../types'; -import { DataManager } from './data/data-manager'; -import { EventQuery } from './data/data-types'; +import { CameraManager } from '../camera/manager'; +import { EventQuery } from '../camera/types'; import { RecordingSegment, RecordingSegments } from './frigate'; -import { capEndDate, convertRangeToCacheFriendlyTimes } from './data/data-manager-util'; +import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera/util'; import { EventMediaQueries } from '../view'; import { ViewMedia } from '../view-media'; -import { - compressRanges, - ExpiringMemoryRangeSet, - MemoryRangeSet, -} from './data/data-manager-range'; +import { compressRanges, ExpiringMemoryRangeSet, MemoryRangeSet } from '../camera/range'; import { ModifyInterface } from './basic'; // Allow timeline freshness to be at least this number of seconds out of date @@ -36,7 +32,7 @@ export interface FrigateCardTimelineItem extends TimelineItem { } export class TimelineDataSource { - protected _dataManager: DataManager; + protected _cameraManager: CameraManager; protected _dataset: DataSet = new DataSet(); // The ranges in which recordings have been calculated and added for. @@ -53,11 +49,11 @@ export class TimelineDataSource { protected _mediaType: ClipsOrSnapshotsOrAll; constructor( - dataManager: DataManager, + cameraManager: CameraManager, cameraIDs: Set, media: ClipsOrSnapshotsOrAll, ) { - this._dataManager = dataManager; + this._cameraManager = cameraManager; this._cameraIDs = cameraIDs; this._mediaType = media; } @@ -108,7 +104,7 @@ export class TimelineDataSource { } public getTimelineEventQueries(window: TimelineWindow): EventQuery[] { - return this._dataManager.generateDefaultEventQueries(this._cameraIDs, { + return this._cameraManager.generateDefaultEventQueries(this._cameraIDs, { start: window.start, end: window.end, ...(this._mediaType === 'clips' && { hasClip: true }), @@ -137,7 +133,7 @@ export class TimelineDataSource { this.getTimelineEventQueries(cacheFriendlyWindow), ); - const results = await this._dataManager.executeMediaQuery(hass, query); + const results = await this._cameraManager.executeMediaQuery(hass, query); for (const media of results?.getResults() ?? []) { const endTime = media.getEndTime(); const startTime = media.getStartTime(); @@ -222,7 +218,7 @@ export class TimelineDataSource { endCap: true, }); - const queries = this._dataManager.generateDefaultRecordingSegmentsQueries( + const queries = this._cameraManager.generateDefaultRecordingSegmentsQueries( this._cameraIDs, { start: cacheFriendlyWindow.start, @@ -230,7 +226,7 @@ export class TimelineDataSource { }, ); - const results = await this._dataManager.getRecordingSegments(hass, queries); + const results = await this._cameraManager.getRecordingSegments(hass, queries); const newSegments: Map = new Map(); for (const [query, result] of results) { diff --git a/src/view.ts b/src/view.ts index 8a10bea4..13aac7f8 100644 --- a/src/view.ts +++ b/src/view.ts @@ -1,5 +1,5 @@ // Easy: -// - TODO: Search for references to frigate.js and see where it's being called outside of the dataManager. Can I collapse some of those functions in? +// - TODO: Search for references to frigate.js and see where it's being called outside of the cameraManager. Can I collapse some of those functions in? // - TODO: Refactor thumbnailsControlSchema to all use the shortform for other thumbnail users beyond live. // - TODO: limit param in recordings should do something // - TODO: Should be able to set live media to 'all' and have it work. @@ -36,7 +36,7 @@ import { FRIGATE_CARD_VIEW_DEFAULT, } from './types.js'; import { dispatchFrigateCardEvent } from './utils/basic.js'; -import { EventQuery, MediaQuery, RecordingQuery } from './utils/data/data-types.js'; +import { EventQuery, MediaQuery, RecordingQuery } from './camera/types.js'; import { ViewMedia } from './view-media.js'; export interface ViewEvolveParameters {