Refactor camera initialization into the camera engines.
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import galleryStyle from '../scss/gallery.scss';
|
||||
import {
|
||||
CameraConfig,
|
||||
CardWideConfig,
|
||||
ExtendedHomeAssistant,
|
||||
frigateCardConfigDefaults,
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
} from '../utils/media-to-view.js';
|
||||
import { CameraManager, ExtendedMediaQueryResult } from '../camera-manager/manager.js';
|
||||
import { View } from '../view/view.js';
|
||||
import { renderProgressIndicator } from './message.js';
|
||||
import { dispatchMessageEvent, renderProgressIndicator } from './message.js';
|
||||
import './thumbnail.js';
|
||||
import { THUMBNAIL_DETAILS_WIDTH_MIN } from './thumbnail.js';
|
||||
import { createRef, Ref } from 'lit/directives/ref.js';
|
||||
@@ -36,6 +35,7 @@ import { errorToConsole } from '../utils/basic';
|
||||
import './media-filter';
|
||||
import "./surround-basic";
|
||||
import { ViewMedia } from '../view/media';
|
||||
import { localize } from '../localize/localize';
|
||||
|
||||
const GALLERY_MEDIA_CHUNK_SIZE = 100;
|
||||
|
||||
@@ -55,9 +55,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public galleryConfig?: GalleryConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@@ -72,7 +69,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
if (
|
||||
!this.hass ||
|
||||
!this.view ||
|
||||
!this.cameras ||
|
||||
!this.view.isGalleryView() ||
|
||||
!this.cameraManager
|
||||
) {
|
||||
@@ -85,7 +81,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
);
|
||||
} else {
|
||||
@@ -98,7 +93,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
...(mediaType && { mediaType: mediaType }),
|
||||
@@ -120,7 +114,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
${this.galleryConfig && this.galleryConfig.controls.filter.mode !== 'none'
|
||||
? html` <frigate-card-media-filter
|
||||
.hass=${this.hass}
|
||||
.cameras=${this.cameras}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.view=${this.view}
|
||||
.mediaLimit=${GALLERY_MEDIA_CHUNK_SIZE}
|
||||
@@ -132,7 +125,6 @@ export class FrigateCardGallery extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.view=${this.view}
|
||||
.galleryConfig=${this.galleryConfig}
|
||||
.cameras=${this.cameras}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
>
|
||||
@@ -166,9 +158,6 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public galleryConfig?: GalleryConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@@ -330,12 +319,17 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
!this._media ||
|
||||
!this.hass ||
|
||||
!this.view ||
|
||||
!this.view.isGalleryView() ||
|
||||
!this.cameras
|
||||
!this.view.isGalleryView()
|
||||
) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
if ((this.view?.queryResults?.getResultsCount() ?? 0) === 0) {
|
||||
return dispatchMessageEvent(this, localize('common.no_media'), 'info', {
|
||||
icon: 'mdi:multimedia',
|
||||
});
|
||||
}
|
||||
|
||||
return html`
|
||||
${this._media.map(
|
||||
(media, index) =>
|
||||
|
||||
+20
-23
@@ -104,9 +104,6 @@ export class FrigateCardLive extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public view?: Readonly<View>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public liveConfig?: LiveConfig;
|
||||
|
||||
@@ -200,7 +197,7 @@ export class FrigateCardLive extends LitElement {
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.liveConfig || !this.cameras || !this.view) {
|
||||
if (!this.hass || !this.liveConfig || !this.cameraManager || !this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,7 +226,6 @@ export class FrigateCardLive extends LitElement {
|
||||
.fetchMedia=${config.controls.thumbnails.media}
|
||||
.thumbnailConfig=${config.controls.thumbnails}
|
||||
.timelineConfig=${config.controls.timeline}
|
||||
.cameras=${this.cameras}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.inBackground=${this._inBackground}
|
||||
@frigate-card:message=${(ev: CustomEvent<Message>) => {
|
||||
@@ -254,7 +250,6 @@ export class FrigateCardLive extends LitElement {
|
||||
<frigate-card-live-carousel
|
||||
.hass=${this.hass}
|
||||
.view=${this.view}
|
||||
.cameras=${this.cameras}
|
||||
.liveConfig=${this.liveConfig}
|
||||
.inBackground=${this._inBackground}
|
||||
.conditionState=${this.conditionState}
|
||||
@@ -286,9 +281,6 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public view?: Readonly<View>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public liveConfig?: LiveConfig;
|
||||
|
||||
@@ -345,10 +337,11 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
}
|
||||
|
||||
protected _getSelectedCameraIndex(): number {
|
||||
if (!this.cameras || !this.view) {
|
||||
const cameraIDs = this.cameraManager?.getCameraIDs();
|
||||
if (!cameraIDs || !this.view) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, Array.from(this.cameras.keys()).indexOf(this.view.camera));
|
||||
return Math.max(0, Array.from(cameraIDs).indexOf(this.view.camera));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,9 +360,10 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* @returns A list of EmblaOptionsTypes.
|
||||
*/
|
||||
protected _getPlugins(): EmblaCarouselPlugins {
|
||||
const cameras = this.cameraManager?.getCameraIDs();
|
||||
return [
|
||||
// Only enable wheel plugin if there is more than one camera.
|
||||
...(this.cameras && this.cameras.size > 1
|
||||
...(cameras && cameras.size > 1
|
||||
? [
|
||||
WheelGesturesPlugin({
|
||||
// Whether the carousel is vertical or horizontal, interpret y-axis wheel
|
||||
@@ -424,14 +418,15 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* name to slide number.
|
||||
*/
|
||||
protected _getSlides(): [TemplateResult[], Record<string, number>] {
|
||||
if (!this.cameras) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!cameras) {
|
||||
return [[], {}];
|
||||
}
|
||||
|
||||
const slides: TemplateResult[] = [];
|
||||
const cameraToSlide: Record<string, number> = {};
|
||||
|
||||
for (const [camera, cameraConfig] of this.cameras) {
|
||||
for (const [camera, cameraConfig] of cameras) {
|
||||
const slide = this._renderLive(camera, cameraConfig, slides.length);
|
||||
if (slide) {
|
||||
cameraToSlide[camera] = slides.length;
|
||||
@@ -445,8 +440,9 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* Handle the user selecting a new slide in the carousel.
|
||||
*/
|
||||
protected _setViewHandler(ev: CustomEvent<CarouselSelect>): void {
|
||||
if (this.cameras && ev.detail.index !== this._getSelectedCameraIndex()) {
|
||||
this._setViewCameraID(Array.from(this.cameras.keys())[ev.detail.index]);
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (cameras && ev.detail.index !== this._getSelectedCameraIndex()) {
|
||||
this._setViewCameraID(Array.from(cameras.keys())[ev.detail.index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,19 +530,20 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
}
|
||||
|
||||
protected _getCameraIDsOfNeighbors(): [string | null, string | null] {
|
||||
if (!this.cameras || !this.view || !this.hass) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!cameras || !this.view || !this.hass) {
|
||||
return [null, null];
|
||||
}
|
||||
const keys = Array.from(this.cameras.keys());
|
||||
const keys = Array.from(cameras.keys());
|
||||
const currentIndex = keys.indexOf(this.view.camera);
|
||||
|
||||
if (currentIndex < 0 || this.cameras.size <= 1) {
|
||||
if (currentIndex < 0 || cameras.size <= 1) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
return [
|
||||
keys[currentIndex > 0 ? currentIndex - 1 : this.cameras.size - 1],
|
||||
keys[currentIndex + 1 < this.cameras.size ? currentIndex + 1 : 0],
|
||||
keys[currentIndex > 0 ? currentIndex - 1 : cameras.size - 1],
|
||||
keys[currentIndex + 1 < cameras.size ? currentIndex + 1 : 0],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -602,11 +599,11 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
<frigate-card-media-carousel
|
||||
${ref(this._refMediaCarousel)}
|
||||
.carouselOptions=${guard(
|
||||
[this.cameras, this.liveConfig],
|
||||
[this.cameraManager, this.liveConfig],
|
||||
this._getOptions.bind(this),
|
||||
)}
|
||||
.carouselPlugins=${guard(
|
||||
[this.cameras, this.liveConfig],
|
||||
[this.cameraManager, this.liveConfig],
|
||||
this._getPlugins.bind(this),
|
||||
) as EmblaCarouselPlugins}
|
||||
.label="${cameraMetadataCurrent ? `${localize('common.live')}: ${cameraMetadataCurrent.title}` : ''}"
|
||||
|
||||
@@ -13,7 +13,6 @@ import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||
import { DateRange } from '../camera-manager/range';
|
||||
import { localize } from '../localize/localize';
|
||||
import mediaFilterStyle from '../scss/media-filter.scss';
|
||||
import { CameraConfig } from '../types';
|
||||
import { createViewForEvents, createViewForRecordings } from '../utils/media-to-view.js';
|
||||
import { errorToConsole, formatDate, prettifyTitle } from '../utils/basic';
|
||||
import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin';
|
||||
@@ -77,9 +76,6 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
@property({ attribute: false })
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@@ -173,7 +169,8 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_ev: CustomEvent<{ value: unknown }>,
|
||||
): Promise<void> {
|
||||
if (!this.hass || !this.cameras || !this.cameraManager || !this.view) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!this.hass || !cameras || !this.cameraManager || !this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,7 +184,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
};
|
||||
|
||||
const cameraIDs =
|
||||
getArrayValueAsSet(this._refCamera.value?.value) ?? new Set(this.cameras.keys());
|
||||
getArrayValueAsSet(this._refCamera.value?.value) ?? new Set(cameras.keys());
|
||||
const mediaType = this._refMediaType.value?.value as
|
||||
| MediaFilterMediaType
|
||||
| undefined;
|
||||
@@ -229,20 +226,13 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
];
|
||||
|
||||
(
|
||||
await createViewForEvents(
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
query: new EventMediaQueries(queries),
|
||||
await createViewForEvents(this, this.hass, this.cameraManager, this.view, {
|
||||
query: new EventMediaQueries(queries),
|
||||
|
||||
// See 'A note on views' above for these two arguments.
|
||||
...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }),
|
||||
targetView: mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots',
|
||||
},
|
||||
)
|
||||
// See 'A note on views' above for these two arguments.
|
||||
...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }),
|
||||
targetView: mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots',
|
||||
})
|
||||
)?.dispatchChangeEvent(this);
|
||||
} else if (mediaType === MediaFilterMediaType.Recordings) {
|
||||
const query: RecordingQuery = {
|
||||
@@ -252,32 +242,28 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
};
|
||||
|
||||
(
|
||||
await createViewForRecordings(
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
query: new RecordingMediaQueries([query]),
|
||||
await createViewForRecordings(this, this.hass, this.cameraManager, this.view, {
|
||||
query: new RecordingMediaQueries([query]),
|
||||
|
||||
// See 'A note on views' above for these two arguments.
|
||||
...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }),
|
||||
targetView: 'recordings',
|
||||
},
|
||||
)
|
||||
// See 'A note on views' above for these two arguments.
|
||||
...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }),
|
||||
targetView: 'recordings',
|
||||
})
|
||||
)?.dispatchChangeEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
if (changedProps.has('cameras') && this.cameras) {
|
||||
this._cameraOptions = Array.from(this.cameras.keys()).map((cameraID) => ({
|
||||
value: cameraID,
|
||||
label: this.hass
|
||||
? this.cameraManager?.getCameraMetadata(this.hass, cameraID)?.title ?? ''
|
||||
: '',
|
||||
}));
|
||||
if (changedProps.has('cameraManager')) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (cameras) {
|
||||
this._cameraOptions = Array.from(cameras.keys()).map((cameraID) => ({
|
||||
value: cameraID,
|
||||
label: this.hass
|
||||
? this.cameraManager?.getCameraMetadata(this.hass, cameraID)?.title ?? ''
|
||||
: '',
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProps.has('cameraManager') && this.hass && this.cameraManager) {
|
||||
@@ -321,7 +307,8 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
|
||||
protected _getDefaultsFromView(): MediaFilterCoreDefaults | null {
|
||||
const queries = this.view?.query?.getQueries();
|
||||
if (!this.view || !queries) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!this.view || !queries || !cameras) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -337,7 +324,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
);
|
||||
// Special note: If all cameras are selected, this is the same as no
|
||||
// selector at all.
|
||||
if (cameraIDSets.length === 1 && queries[0].cameraIDs.size !== this.cameras?.size) {
|
||||
if (cameraIDSets.length === 1 && queries[0].cameraIDs.size !== cameras.size) {
|
||||
cameraIDs = [...queries[0].cameraIDs];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import surroundStyle from '../scss/surround.scss';
|
||||
import {
|
||||
CameraConfig,
|
||||
ClipsOrSnapshotsOrAll,
|
||||
ExtendedHomeAssistant,
|
||||
MiniTimelineControlConfig,
|
||||
@@ -55,9 +54,6 @@ export class FrigateCardSurround extends LitElement {
|
||||
@property({ attribute: false, hasChanged: contentsChanged })
|
||||
public fetchMedia?: ClipsOrSnapshotsOrAll;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@@ -71,7 +67,6 @@ export class FrigateCardSurround extends LitElement {
|
||||
*/
|
||||
protected async _fetchMedia(): Promise<void> {
|
||||
if (
|
||||
!this.cameras ||
|
||||
!this.cameraManager ||
|
||||
!this.fetchMedia ||
|
||||
this.inBackground ||
|
||||
@@ -88,7 +83,6 @@ export class FrigateCardSurround extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
targetView: this.view.view,
|
||||
@@ -138,11 +132,12 @@ export class FrigateCardSurround extends LitElement {
|
||||
}
|
||||
|
||||
protected _getCameraIDsForTimeline(): Set<string> | null {
|
||||
if (!this.view || !this.cameras) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!this.view || !cameras) {
|
||||
return null;
|
||||
}
|
||||
if (this.view?.is('live')) {
|
||||
return getAllDependentCameras(this.cameras, this.view.camera);
|
||||
return getAllDependentCameras(cameras, this.view.camera);
|
||||
}
|
||||
if (this.view.isViewerView()) {
|
||||
return new Set(
|
||||
@@ -160,7 +155,7 @@ export class FrigateCardSurround extends LitElement {
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.view || !this.thumbnailConfig || !this.cameras) {
|
||||
if (!this.hass || !this.view || !this.thumbnailConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +215,6 @@ export class FrigateCardSurround extends LitElement {
|
||||
slot=${this.timelineConfig.mode}
|
||||
.hass=${this.hass}
|
||||
.view=${this.view}
|
||||
.cameras=${this.cameras}
|
||||
.cameraIDs=${this._cameraIDsForTimeline}
|
||||
.mini=${true}
|
||||
.timelineConfig=${this.timelineConfig}
|
||||
|
||||
@@ -13,7 +13,6 @@ import { classMap } from 'lit/directives/class-map.js';
|
||||
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
|
||||
import {
|
||||
CameraConfig,
|
||||
ExtendedHomeAssistant,
|
||||
ThumbnailsControlConfig,
|
||||
} from '../types.js';
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
TimelineOptionsCluster,
|
||||
TimelineWindow,
|
||||
} from 'vis-timeline/esnext';
|
||||
import { CAMERA_BIRDSEYE } from '../const';
|
||||
import { localize } from '../localize/localize';
|
||||
import timelineCoreStyle from '../scss/timeline-core.scss';
|
||||
import {
|
||||
@@ -165,9 +164,6 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public view?: Readonly<View>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false, hasChanged: contentsChanged })
|
||||
public timelineConfig?: TimelineCoreConfig;
|
||||
|
||||
@@ -240,11 +236,12 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
protected _handleThumbnailDataRequest(request: ThumbnailDataRequestEvent): void {
|
||||
const item = request.detail.item;
|
||||
const media = this._timelineSource?.dataset.get(item)?.media;
|
||||
const cameraConfig = media
|
||||
? this.cameraManager?.getCameraConfig(media.getCameraID()) ?? undefined
|
||||
: undefined;
|
||||
|
||||
request.detail.hass = this.hass;
|
||||
request.detail.cameraConfig = media
|
||||
? this.cameras?.get(media.getCameraID())
|
||||
: undefined;
|
||||
request.detail.cameraConfig = cameraConfig;
|
||||
request.detail.cameraManager = this.cameraManager;
|
||||
request.detail.media = media;
|
||||
request.detail.view = this.view;
|
||||
@@ -255,13 +252,13 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.view || !this.timelineConfig) {
|
||||
const cameraIDs = this._getTimelineCameraIDs();
|
||||
|
||||
if (!this.hass || !this.view || !this.timelineConfig || !cameraIDs) {
|
||||
return;
|
||||
}
|
||||
const capabilities = this.cameraManager?.getAggregateCameraCapabilities(
|
||||
this._getTimelineCameraIDs(),
|
||||
);
|
||||
|
||||
const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs);
|
||||
return html` ${capabilities?.supportsTimeline
|
||||
? html` <div
|
||||
@frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind(
|
||||
@@ -292,7 +289,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
* Get all the keys of the cameras in scope for this timeline.
|
||||
* @returns A set of camera ids (may be empty).
|
||||
*/
|
||||
protected _getTimelineCameraIDs(): Set<string> {
|
||||
protected _getTimelineCameraIDs(): Set<string> | null {
|
||||
return this.cameraIDs ?? this._getAllCameraIDs();
|
||||
}
|
||||
|
||||
@@ -300,8 +297,8 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
* Get all the keys of all cameras.
|
||||
* @returns A set of camera ids (may be empty).
|
||||
*/
|
||||
protected _getAllCameraIDs(): Set<string> {
|
||||
return new Set(this.cameras?.keys());
|
||||
protected _getAllCameraIDs(): Set<string> | null {
|
||||
return this.cameraManager?.getCameraIDs() ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,6 +392,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
): Promise<void> {
|
||||
const results = this.view?.queryResults;
|
||||
const media = results?.getResults();
|
||||
const cameraIDs = this._getTimelineCameraIDs();
|
||||
if (
|
||||
!media ||
|
||||
!results ||
|
||||
@@ -402,7 +400,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
!this.view ||
|
||||
!this.hass ||
|
||||
!this.cameraManager ||
|
||||
!this.cameraManager ||
|
||||
!cameraIDs ||
|
||||
// Skip range changes that do not have hammerjs pan directions associated
|
||||
// with them, as these outliers cause media matching issues below.
|
||||
!properties.event.additionalEvent
|
||||
@@ -420,7 +418,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
findClosestMediaIndex(
|
||||
media,
|
||||
targetTime,
|
||||
this._getTimelineCameraIDs(),
|
||||
cameraIDs,
|
||||
properties.event.additionalEvent === 'panright' ? 'end' : 'start',
|
||||
),
|
||||
);
|
||||
@@ -462,13 +460,14 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
stopEventFromActivatingCardWideActions(properties.event);
|
||||
}
|
||||
|
||||
const timelineCameraIDs = this._getTimelineCameraIDs();
|
||||
if (
|
||||
this._ignoreClick ||
|
||||
!this.hass ||
|
||||
!this._timeline ||
|
||||
!this.cameras ||
|
||||
!this.view ||
|
||||
!this.cameraManager ||
|
||||
!timelineCameraIDs ||
|
||||
!properties.what
|
||||
) {
|
||||
return;
|
||||
@@ -484,7 +483,6 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
targetTime:
|
||||
@@ -501,10 +499,9 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
cameraIDs: this._getAllCameraIDs(),
|
||||
cameraIDs: timelineCameraIDs,
|
||||
start: startOfHour(properties.time),
|
||||
end: endOfHour(properties.time),
|
||||
targetTime: properties.time,
|
||||
@@ -514,9 +511,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
const newResults = this.view.queryResults
|
||||
?.clone()
|
||||
.resetSelectedResult()
|
||||
.selectResultIfFound(
|
||||
(media) => !!this.cameras && media.getID() === properties.item,
|
||||
);
|
||||
.selectResultIfFound((media) => media.getID() === properties.item);
|
||||
|
||||
if (!newResults || !newResults.hasSelectedResult()) {
|
||||
// This can happen if this is a recording query (with recorded hours)
|
||||
@@ -588,7 +583,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
}
|
||||
this._removeTargetBar();
|
||||
|
||||
if (!this.hass || !this.cameras) {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -646,14 +641,13 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
selectedItem?: IdType;
|
||||
},
|
||||
): Promise<View | null> {
|
||||
if (!this.hass || !this.cameraManager || !this.cameras || !this.view || !query) {
|
||||
if (!this.hass || !this.cameraManager || !this.view || !query) {
|
||||
return null;
|
||||
}
|
||||
const view = await createViewForEvents(
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
query: query,
|
||||
@@ -666,7 +660,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
}
|
||||
if (options?.selectedItem) {
|
||||
view.queryResults?.selectResultIfFound(
|
||||
(media) => !!this.cameras && media.getID() === options.selectedItem,
|
||||
(media) => media.getID() === options.selectedItem,
|
||||
);
|
||||
} else {
|
||||
// If not asked to select a new item, persist the currently selected item
|
||||
@@ -687,10 +681,8 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
*/
|
||||
protected _getGroups(): DataGroupCollectionType {
|
||||
const groups: FrigateCardGroupData[] = [];
|
||||
|
||||
this._getTimelineCameraIDs().forEach((cameraID) => {
|
||||
const cameraConfig = this.cameras?.get(cameraID);
|
||||
if (!this.hass || !cameraConfig || !this.cameraManager) {
|
||||
(this._getTimelineCameraIDs() ?? []).forEach((cameraID) => {
|
||||
if (!this.hass || !this.cameraManager) {
|
||||
return;
|
||||
}
|
||||
const cameraMetadata = this.cameraManager.getCameraMetadata(this.hass, cameraID);
|
||||
@@ -806,10 +798,6 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
maxItems: this.timelineConfig.clustering_threshold,
|
||||
|
||||
clusterCriteria: (first: TimelineItem, second: TimelineItem): boolean => {
|
||||
if (!this.cameras) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const media = this.view?.queryResults?.getSelectedResult();
|
||||
const selectedId = media?.getID();
|
||||
const firstMedia = (<FrigateCardTimelineItem>first).media;
|
||||
@@ -866,7 +854,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
protected shouldUpdate(_changedProps: PropertyValues): boolean {
|
||||
return !!this.hass && !!this.cameras && this.cameras.size > 0;
|
||||
return !!this.hass && !!this.cameraManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -875,7 +863,6 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
protected async _updateTimelineFromView(): Promise<void> {
|
||||
if (
|
||||
!this.hass ||
|
||||
!this.cameras ||
|
||||
!this.view ||
|
||||
!this.timelineConfig ||
|
||||
!this._timelineSource ||
|
||||
@@ -1040,10 +1027,11 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
changedProps.has('timelineConfig') ||
|
||||
changedProps.has('cameraIDs')
|
||||
) {
|
||||
if (this.cameraManager && this.cameras && this.timelineConfig) {
|
||||
const cameraIDs = this._getTimelineCameraIDs();
|
||||
if (cameraIDs && this.cameraManager && this.timelineConfig) {
|
||||
this._timelineSource = new TimelineDataSource(
|
||||
this.cameraManager,
|
||||
this._getTimelineCameraIDs(),
|
||||
cameraIDs,
|
||||
this.timelineConfig.media,
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,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 { ExtendedHomeAssistant, TimelineConfig } from '../types';
|
||||
import { CameraManager } from '../camera-manager/manager';
|
||||
import { View } from '../view/view';
|
||||
import './surround.js';
|
||||
@@ -20,9 +20,6 @@ export class FrigateCardTimeline extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public view?: Readonly<View>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public timelineConfig?: TimelineConfig;
|
||||
|
||||
@@ -43,12 +40,10 @@ export class FrigateCardTimeline extends LitElement {
|
||||
.view=${this.view}
|
||||
.thumbnailConfig=${this.timelineConfig.controls.thumbnails}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.cameras=${this.cameras}
|
||||
>
|
||||
<frigate-card-timeline-core
|
||||
.hass=${this.hass}
|
||||
.view=${this.view}
|
||||
.cameras=${this.cameras}
|
||||
.timelineConfig=${this.timelineConfig}
|
||||
.thumbnailDetails=${this.timelineConfig.controls.thumbnails.show_details}
|
||||
.thumbnailSize=${this.timelineConfig.controls.thumbnails.size}
|
||||
|
||||
@@ -16,7 +16,6 @@ import { dispatchMessageEvent, renderProgressIndicator } from '../components/mes
|
||||
import viewerStyle from '../scss/viewer.scss';
|
||||
import viewerCarouselStyle from '../scss/viewer-carousel.scss';
|
||||
import {
|
||||
CameraConfig,
|
||||
CardWideConfig,
|
||||
ExtendedHomeAssistant,
|
||||
frigateCardConfigDefaults,
|
||||
@@ -78,9 +77,6 @@ export class FrigateCardViewer extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public viewerConfig?: ViewerConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public resolvedMediaCache?: ResolvedMediaCache;
|
||||
|
||||
@@ -98,7 +94,6 @@ export class FrigateCardViewer extends LitElement {
|
||||
if (
|
||||
!this.hass ||
|
||||
!this.view ||
|
||||
!this.cameras ||
|
||||
!this.viewerConfig ||
|
||||
!this.cameraManager
|
||||
) {
|
||||
@@ -120,7 +115,6 @@ export class FrigateCardViewer extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
targetView: 'recording',
|
||||
@@ -131,7 +125,6 @@ export class FrigateCardViewer extends LitElement {
|
||||
this,
|
||||
this.hass,
|
||||
this.cameraManager,
|
||||
this.cameras,
|
||||
this.view,
|
||||
{
|
||||
targetView: 'media',
|
||||
@@ -148,12 +141,10 @@ export class FrigateCardViewer extends LitElement {
|
||||
.thumbnailConfig=${this.viewerConfig.controls.thumbnails}
|
||||
.timelineConfig=${this.viewerConfig.controls.timeline}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.cameras=${this.cameras}
|
||||
>
|
||||
<frigate-card-viewer-carousel
|
||||
.hass=${this.hass}
|
||||
.view=${this.view}
|
||||
.cameras=${this.cameras}
|
||||
.viewerConfig=${this.viewerConfig}
|
||||
.resolvedMediaCache=${this.resolvedMediaCache}
|
||||
.cameraManager=${this.cameraManager}
|
||||
@@ -195,9 +186,6 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public cardWideConfig?: CardWideConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameras?: Map<string, CameraConfig>;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@@ -205,19 +193,17 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
|
||||
// A task to resolve target media if lazy loading is disabled.
|
||||
protected _mediaResolutionTask = new Task<
|
||||
[ViewerConfig | undefined, Map<string, CameraConfig> | undefined, View | undefined],
|
||||
[ViewerConfig | undefined, View | undefined],
|
||||
void
|
||||
>(
|
||||
this,
|
||||
async ([viewerConfig, cameras, view]: [
|
||||
async ([viewerConfig, view]: [
|
||||
ViewerConfig | undefined,
|
||||
Map<string, CameraConfig> | undefined,
|
||||
View | undefined,
|
||||
]): Promise<void> => {
|
||||
if (
|
||||
!this.hass ||
|
||||
!viewerConfig?.lazy_load ||
|
||||
!cameras ||
|
||||
!view ||
|
||||
!view.queryResults?.hasResults()
|
||||
) {
|
||||
@@ -234,7 +220,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
});
|
||||
await Promise.all(promises);
|
||||
},
|
||||
() => [this.viewerConfig, this.cameras, this.view],
|
||||
() => [this.viewerConfig, this.view],
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -453,7 +439,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
* @param slide The slide to lazy load.
|
||||
*/
|
||||
protected _lazyloadSlide(index: number, slide: HTMLElement): void {
|
||||
if (!this.hass || !this.view || !this.view.query || !this.cameras) {
|
||||
if (!this.hass || !this.view || !this.view.query) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -512,7 +498,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
* Determine if all the media in the carousel are resolved.
|
||||
*/
|
||||
protected _isMediaFullyResolved(): boolean {
|
||||
if (!this.resolvedMediaCache || !this.cameras) {
|
||||
if (!this.resolvedMediaCache) {
|
||||
return false;
|
||||
}
|
||||
for (const media of this.view?.queryResults?.getResults() ?? []) {
|
||||
@@ -560,7 +546,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
}
|
||||
|
||||
const media = this.view?.queryResults?.getSelectedResult();
|
||||
if (!media || !this.cameras || !this.view || !this.view.queryResults) {
|
||||
if (!media || !this.view || !this.view.queryResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -649,7 +635,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
*/
|
||||
protected _renderMediaItem(media: ViewMedia, index: number): TemplateResult | null {
|
||||
// Skip folders as they cannot be rendered by this viewer.
|
||||
if (!this.hass || !this.view || !this.viewerConfig || !this.cameras) {
|
||||
if (!this.hass || !this.view || !this.viewerConfig) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user