Don't show the timeline if no cameras support it.
This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
|||||||
RecordingQueryResultsMap,
|
RecordingQueryResultsMap,
|
||||||
RecordingSegmentsQuery,
|
RecordingSegmentsQuery,
|
||||||
RecordingSegmentsQueryResultsMap,
|
RecordingSegmentsQueryResultsMap,
|
||||||
CameraManagerEngineCapabilities,
|
CameraManagerCameraCapabilities,
|
||||||
CameraManagerMediaCapabilities,
|
CameraManagerMediaCapabilities,
|
||||||
CameraManagerCameraMetadata,
|
CameraManagerCameraMetadata,
|
||||||
} from './types';
|
} from './types';
|
||||||
@@ -100,6 +100,9 @@ export interface CameraManagerEngine {
|
|||||||
cameraConfig: CameraConfig,
|
cameraConfig: CameraConfig,
|
||||||
): CameraManagerCameraMetadata;
|
): CameraManagerCameraMetadata;
|
||||||
|
|
||||||
getCapabilities(): CameraManagerEngineCapabilities | null;
|
getCameraCapabilities(
|
||||||
|
cameraConfig: CameraConfig,
|
||||||
|
): CameraManagerCameraCapabilities | null;
|
||||||
|
|
||||||
getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null;
|
getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
import { DateRange } from '../range';
|
import { DateRange } from '../range';
|
||||||
import {
|
import {
|
||||||
CameraManagerCameraMetadata,
|
CameraManagerCameraMetadata,
|
||||||
CameraManagerEngineCapabilities,
|
CameraManagerCameraCapabilities,
|
||||||
CameraManagerMediaCapabilities,
|
CameraManagerMediaCapabilities,
|
||||||
DataQuery,
|
DataQuery,
|
||||||
Engine,
|
Engine,
|
||||||
@@ -805,10 +805,14 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
|
|||||||
return seekMilliseconds / 1000;
|
return seekMilliseconds / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCapabilities(): CameraManagerEngineCapabilities {
|
public getCameraCapabilities(
|
||||||
|
cameraConfig: CameraConfig,
|
||||||
|
): CameraManagerCameraCapabilities {
|
||||||
|
const isBirdseye = cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE;
|
||||||
return {
|
return {
|
||||||
canFavoriteEvents: true,
|
canFavoriteEvents: !isBirdseye,
|
||||||
canFavoriteRecordings: false,
|
canFavoriteRecordings: !isBirdseye,
|
||||||
|
supportsTimeline: !isBirdseye,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { HomeAssistant } from 'custom-card-helpers';
|
|||||||
import { CameraConfig, CardWideConfig } from '../types.js';
|
import { CameraConfig, CardWideConfig } from '../types.js';
|
||||||
import { allPromises, arrayify, setify } from '../utils/basic.js';
|
import { allPromises, arrayify, setify } from '../utils/basic.js';
|
||||||
import {
|
import {
|
||||||
|
CameraManagerCameraCapabilities,
|
||||||
CameraManagerCameraMetadata,
|
CameraManagerCameraMetadata,
|
||||||
CameraManagerCapabilities,
|
CameraManagerCapabilities,
|
||||||
CameraManagerMediaCapabilities,
|
CameraManagerMediaCapabilities,
|
||||||
@@ -312,22 +313,6 @@ export class CameraManager {
|
|||||||
return engine.getMediaDownloadPath(cameraConfig, media);
|
return engine.getMediaDownloadPath(cameraConfig, media);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCapabilities(): CameraManagerCapabilities | null {
|
|
||||||
const engines = this._engineFactory.getAllEngines(this._cameras);
|
|
||||||
if (!engines) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
canFavoriteEvents: engines.some(
|
|
||||||
(engine) => engine.getCapabilities()?.canFavoriteEvents,
|
|
||||||
),
|
|
||||||
canFavoriteRecordings: engines.some(
|
|
||||||
(engine) => engine.getCapabilities()?.canFavoriteRecordings,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null {
|
public getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null {
|
||||||
const engine = this._engineFactory.getEngineForMedia(this._cameras, media);
|
const engine = this._engineFactory.getEngineForMedia(this._cameras, media);
|
||||||
if (!engine) {
|
if (!engine) {
|
||||||
@@ -534,12 +519,45 @@ export class CameraManager {
|
|||||||
|
|
||||||
public getCameraMetadata(
|
public getCameraMetadata(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
cameraConfig?: CameraConfig,
|
cameraID: string,
|
||||||
): CameraManagerCameraMetadata | null {
|
): CameraManagerCameraMetadata | null {
|
||||||
|
const cameraConfig = this._cameras.get(cameraID);
|
||||||
const engine = this._engineFactory.getEngineForCamera(cameraConfig);
|
const engine = this._engineFactory.getEngineForCamera(cameraConfig);
|
||||||
if (!engine || !cameraConfig) {
|
if (!engine || !cameraConfig) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return engine.getCameraMetadata(hass, cameraConfig);
|
return engine.getCameraMetadata(hass, cameraConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCameraCapabilities(
|
||||||
|
cameraID: string,
|
||||||
|
): CameraManagerCameraCapabilities | null {
|
||||||
|
const cameraConfig = this._cameras.get(cameraID);
|
||||||
|
if (!cameraConfig) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const engine = this._engineFactory.getEngineForCamera(cameraConfig);
|
||||||
|
if (!engine) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return engine.getCameraCapabilities(cameraConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAggregateCameraCapabilities(
|
||||||
|
cameraIDs?: Set<string>,
|
||||||
|
): CameraManagerCapabilities {
|
||||||
|
const perCameraCapabilities = [...(cameraIDs ?? this._cameras.keys())].map(
|
||||||
|
(cameraID) => this.getCameraCapabilities(cameraID),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
canFavoriteEvents: perCameraCapabilities.some((cap) => cap?.canFavoriteEvents),
|
||||||
|
canFavoriteRecordings: perCameraCapabilities.some(
|
||||||
|
(cap) => cap?.canFavoriteRecordings,
|
||||||
|
),
|
||||||
|
supportsTimeline: perCameraCapabilities.some((cap) => cap?.supportsTimeline),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,10 +85,11 @@ export interface MediaMetadata {
|
|||||||
interface BaseCapabilities {
|
interface BaseCapabilities {
|
||||||
canFavoriteEvents: boolean;
|
canFavoriteEvents: boolean;
|
||||||
canFavoriteRecordings: boolean;
|
canFavoriteRecordings: boolean;
|
||||||
|
supportsTimeline: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CameraManagerCapabilities = BaseCapabilities;
|
export type CameraManagerCapabilities = BaseCapabilities;
|
||||||
export type CameraManagerEngineCapabilities = BaseCapabilities;
|
export type CameraManagerCameraCapabilities = BaseCapabilities;
|
||||||
export interface CameraManagerMediaCapabilities {
|
export interface CameraManagerMediaCapabilities {
|
||||||
canFavorite: boolean;
|
canFavorite: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -399,12 +399,12 @@ class FrigateCard extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this._cameras && this._cameras.size > 1) {
|
if (this._cameras && this._cameras.size > 1) {
|
||||||
const menuItems = Array.from(this._cameras, ([camera, config]) => {
|
const menuItems = Array.from(this._cameras, ([cameraID, config]) => {
|
||||||
const action = createFrigateCardCustomAction('camera_select', {
|
const action = createFrigateCardCustomAction('camera_select', {
|
||||||
camera: camera,
|
camera: cameraID,
|
||||||
});
|
});
|
||||||
const metadata = this._hass
|
const metadata = this._hass
|
||||||
? this._cameraManager?.getCameraMetadata(this._hass, config) ?? undefined
|
? this._cameraManager?.getCameraMetadata(this._hass, cameraID) ?? undefined
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -413,7 +413,7 @@ class FrigateCard extends LitElement {
|
|||||||
entity: config.camera_entity,
|
entity: config.camera_entity,
|
||||||
state_color: true,
|
state_color: true,
|
||||||
title: metadata?.title,
|
title: metadata?.title,
|
||||||
selected: this._view?.camera === camera,
|
selected: this._view?.camera === cameraID,
|
||||||
...(action && { tap_action: action }),
|
...(action && { tap_action: action }),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1427,7 +1427,9 @@ class FrigateCard extends LitElement {
|
|||||||
} else if (this._view?.is('live') && cameraEntity) {
|
} else if (this._view?.is('live') && cameraEntity) {
|
||||||
media_content_id = `media-source://camera/${cameraEntity}`;
|
media_content_id = `media-source://camera/${cameraEntity}`;
|
||||||
media_content_type = 'application/vnd.apple.mpegurl';
|
media_content_type = 'application/vnd.apple.mpegurl';
|
||||||
title = this._cameraManager.getCameraMetadata(this._hass, cameraConfig)?.title ?? null;
|
title =
|
||||||
|
this._cameraManager.getCameraMetadata(this._hass, this._view.camera)?.title ??
|
||||||
|
null;
|
||||||
thumbnail = this._hass?.states[cameraEntity]?.attributes?.entity_picture ?? null;
|
thumbnail = this._hass?.states[cameraEntity]?.attributes?.entity_picture ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,6 @@ export class FrigateCardGalleryCore extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.cameraManager=${this.cameraManager}
|
.cameraManager=${this.cameraManager}
|
||||||
.media=${media}
|
.media=${media}
|
||||||
.cameraConfig=${this.cameras?.get(media.getCameraID())}
|
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
?details=${!!this.galleryConfig?.controls.thumbnails.show_details}
|
?details=${!!this.galleryConfig?.controls.thumbnails.show_details}
|
||||||
?show_favorite_control=${!!this.galleryConfig?.controls.thumbnails
|
?show_favorite_control=${!!this.galleryConfig?.controls.thumbnails
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _renderLive(
|
protected _renderLive(
|
||||||
camera: string,
|
cameraID: string,
|
||||||
cameraConfig: CameraConfig,
|
cameraConfig: CameraConfig,
|
||||||
slideIndex: number,
|
slideIndex: number,
|
||||||
): TemplateResult | void {
|
): TemplateResult | void {
|
||||||
@@ -501,7 +501,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
// <frigate-card-live-provider> is rendering right now.
|
// <frigate-card-live-provider> is rendering right now.
|
||||||
const conditionState = {
|
const conditionState = {
|
||||||
...this.conditionState,
|
...this.conditionState,
|
||||||
camera: camera,
|
camera: cameraID,
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = getOverriddenConfig(
|
const config = getOverriddenConfig(
|
||||||
@@ -510,7 +510,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
conditionState,
|
conditionState,
|
||||||
) as LiveConfig;
|
) as LiveConfig;
|
||||||
|
|
||||||
const cameraMetadata = this.cameraManager.getCameraMetadata(this.hass, cameraConfig);
|
const cameraMetadata = this.cameraManager.getCameraMetadata(this.hass, cameraID);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="embla__slide">
|
<div class="embla__slide">
|
||||||
@@ -560,7 +560,6 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
if (
|
if (
|
||||||
!slides.length ||
|
!slides.length ||
|
||||||
!this.liveConfig ||
|
!this.liveConfig ||
|
||||||
!this.cameras ||
|
|
||||||
!this.view ||
|
!this.view ||
|
||||||
!this.hass ||
|
!this.hass ||
|
||||||
!this.cameraManager
|
!this.cameraManager
|
||||||
@@ -578,15 +577,15 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
|
|
||||||
const cameraMetadataPrevious = prevID ? this.cameraManager.getCameraMetadata(
|
const cameraMetadataPrevious = prevID ? this.cameraManager.getCameraMetadata(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.cameras.get(prevID),
|
prevID,
|
||||||
) : null;
|
) : null;
|
||||||
const cameraMetadataCurrent = this.cameraManager.getCameraMetadata(
|
const cameraMetadataCurrent = this.cameraManager.getCameraMetadata(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.cameras.get(this.view.camera),
|
this.view.camera,
|
||||||
);
|
);
|
||||||
const cameraMetadataNext = nextID ? this.cameraManager.getCameraMetadata(
|
const cameraMetadataNext = nextID ? this.cameraManager.getCameraMetadata(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.cameras.get(nextID),
|
nextID,
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
// Notes on the below:
|
// Notes on the below:
|
||||||
|
|||||||
@@ -272,14 +272,12 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
|||||||
|
|
||||||
protected willUpdate(changedProps: PropertyValues): void {
|
protected willUpdate(changedProps: PropertyValues): void {
|
||||||
if (changedProps.has('cameras') && this.cameras) {
|
if (changedProps.has('cameras') && this.cameras) {
|
||||||
this._cameraOptions = Array.from(this.cameras.entries()).map(
|
this._cameraOptions = Array.from(this.cameras.keys()).map((cameraID) => ({
|
||||||
([cameraID, cameraConfig]) => ({
|
value: cameraID,
|
||||||
value: cameraID,
|
label: this.hass
|
||||||
label: this.hass
|
? this.cameraManager?.getCameraMetadata(this.hass, cameraID)?.title ?? ''
|
||||||
? this.cameraManager?.getCameraMetadata(this.hass, cameraConfig)?.title ?? ''
|
: '',
|
||||||
: '',
|
}));
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedProps.has('cameraManager') && this.hass && this.cameraManager) {
|
if (changedProps.has('cameraManager') && this.hass && this.cameraManager) {
|
||||||
@@ -413,7 +411,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
|||||||
const areRecordings = !!(
|
const areRecordings = !!(
|
||||||
this.view?.query && MediaQueriesClassifier.areRecordingQueries(this.view.query)
|
this.view?.query && MediaQueriesClassifier.areRecordingQueries(this.view.query)
|
||||||
);
|
);
|
||||||
const managerCapabilities = this.cameraManager?.getCapabilities();
|
const managerCapabilities = this.cameraManager?.getAggregateCameraCapabilities();
|
||||||
|
|
||||||
// Which media controls are shown depends on the view.
|
// Which media controls are shown depends on the view.
|
||||||
const showFavoriteControl = areEvents
|
const showFavoriteControl = areEvents
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ export class FrigateCardSurround extends LitElement {
|
|||||||
.config=${this.thumbnailConfig}
|
.config=${this.thumbnailConfig}
|
||||||
.cameraManager=${this.cameraManager}
|
.cameraManager=${this.cameraManager}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.cameras=${this.cameras}
|
|
||||||
.selected=${this.view.queryResults?.getSelectedIndex() ?? undefined}
|
.selected=${this.view.queryResults?.getSelectedIndex() ?? undefined}
|
||||||
@frigate-card:view:change=${(ev: CustomEvent) => changeDrawer(ev, 'close')}
|
@frigate-card:view:change=${(ev: CustomEvent) => changeDrawer(ev, 'close')}
|
||||||
@frigate-card:thumbnail-carousel:tap=${(
|
@frigate-card:thumbnail-carousel:tap=${(
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ export class FrigateCardThumbnailCarousel extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public view?: Readonly<View>;
|
public view?: Readonly<View>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
public cameras?: Map<string, CameraConfig>;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public cameraManager?: CameraManager;
|
public cameraManager?: CameraManager;
|
||||||
|
|
||||||
@@ -150,8 +147,7 @@ export class FrigateCardThumbnailCarousel extends LitElement {
|
|||||||
*/
|
*/
|
||||||
protected _renderThumbnail(index: number): TemplateResult | void {
|
protected _renderThumbnail(index: number): TemplateResult | void {
|
||||||
const media = this.view?.queryResults?.getResult(index) ?? null;
|
const media = this.view?.queryResults?.getResult(index) ?? null;
|
||||||
const cameraConfig = media ? this.cameras?.get(media.getCameraID()) : null;
|
if (!media || !this.view) {
|
||||||
if (!media || !cameraConfig || !this.view) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +162,6 @@ export class FrigateCardThumbnailCarousel extends LitElement {
|
|||||||
.cameraManager=${this.cameraManager}
|
.cameraManager=${this.cameraManager}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.media=${media}
|
.media=${media}
|
||||||
.cameraConfig=${cameraConfig}
|
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.seek=${seekTarget && media.includesTime(seekTarget) ? seekTarget : undefined}
|
.seek=${seekTarget && media.includesTime(seekTarget) ? seekTarget : undefined}
|
||||||
?details=${!!this.config?.show_details}
|
?details=${!!this.config?.show_details}
|
||||||
|
|||||||
+45
-46
@@ -21,7 +21,7 @@ import { createFetchThumbnailTask, FetchThumbnailTaskArgs } from '../utils/thumb
|
|||||||
import { View } from '../view/view.js';
|
import { View } from '../view/view.js';
|
||||||
import { Task, TaskStatus } from '@lit-labs/task';
|
import { Task, TaskStatus } from '@lit-labs/task';
|
||||||
|
|
||||||
import type { CameraConfig, ExtendedHomeAssistant } from '../types.js';
|
import type { ExtendedHomeAssistant } from '../types.js';
|
||||||
import { EventViewMedia, RecordingViewMedia, ViewMedia } from '../view/media.js';
|
import { EventViewMedia, RecordingViewMedia, ViewMedia } from '../view/media.js';
|
||||||
import { CameraManager } from '../camera-manager/manager.js';
|
import { CameraManager } from '../camera-manager/manager.js';
|
||||||
import { ViewMediaClassifier } from '../view/media-classifier.js';
|
import { ViewMediaClassifier } from '../view/media-classifier.js';
|
||||||
@@ -104,12 +104,12 @@ export class FrigateCardThumbnailFeatureEvent extends LitElement {
|
|||||||
|
|
||||||
return html`${this.thumbnail
|
return html`${this.thumbnail
|
||||||
? renderTask(
|
? renderTask(
|
||||||
this,
|
this,
|
||||||
this._embedThumbnailTask,
|
this._embedThumbnailTask,
|
||||||
(embeddedThumbnail: string | null) =>
|
(embeddedThumbnail: string | null) =>
|
||||||
embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``,
|
embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``,
|
||||||
{ inProgressFunc: () => imageOff },
|
{ inProgressFunc: () => imageOff },
|
||||||
)
|
)
|
||||||
: imageOff} `;
|
: imageOff} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export class FrigateCardThumbnailDetailsEvent extends LitElement {
|
|||||||
return html` <div class="left">
|
return html` <div class="left">
|
||||||
${what ? html`<div class="larger">${prettifyTitle(what.join(', '))}</div>` : ``}
|
${what ? html`<div class="larger">${prettifyTitle(what.join(', '))}</div>` : ``}
|
||||||
${startTime
|
${startTime
|
||||||
? html` <div>
|
? html` <div>
|
||||||
<span class="heading">${localize('event.start')}:</span>
|
<span class="heading">${localize('event.start')}:</span>
|
||||||
<span>${format(startTime, 'HH:mm:ss')}</span>
|
<span>${format(startTime, 'HH:mm:ss')}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,17 +170,17 @@ export class FrigateCardThumbnailDetailsEvent extends LitElement {
|
|||||||
<span class="heading">${localize('event.duration')}:</span>
|
<span class="heading">${localize('event.duration')}:</span>
|
||||||
<span
|
<span
|
||||||
>${endTime
|
>${endTime
|
||||||
? getDurationString(startTime, endTime)
|
? getDurationString(startTime, endTime)
|
||||||
: localize('event.in_progress')}</span
|
: localize('event.in_progress')}</span
|
||||||
>
|
>
|
||||||
</div>`
|
</div>`
|
||||||
: ``}
|
: ``}
|
||||||
${this.seek
|
${this.seek
|
||||||
? html` <div>
|
? html` <div>
|
||||||
<span class="heading">${localize('event.seek')}</span>
|
<span class="heading">${localize('event.seek')}</span>
|
||||||
<span>${format(this.seek, 'HH:mm:ss')}</span>
|
<span>${format(this.seek, 'HH:mm:ss')}</span>
|
||||||
</div>`
|
</div>`
|
||||||
: html``}
|
: html``}
|
||||||
</div>
|
</div>
|
||||||
${score
|
${score
|
||||||
? html`<div class="right">
|
? html`<div class="right">
|
||||||
@@ -213,11 +213,11 @@ export class FrigateCardThumbnailDetailsRecording extends LitElement {
|
|||||||
return html`<div class="left">
|
return html`<div class="left">
|
||||||
<div class="larger">${this.cameraTitle ?? ''}</div>
|
<div class="larger">${this.cameraTitle ?? ''}</div>
|
||||||
${this.seek
|
${this.seek
|
||||||
? html` <div>
|
? html` <div>
|
||||||
<span class="heading">${localize('recording.seek')}</span>
|
<span class="heading">${localize('recording.seek')}</span>
|
||||||
<span>${format(this.seek, 'HH:mm:ss')}</span>
|
<span>${format(this.seek, 'HH:mm:ss')}</span>
|
||||||
</div>`
|
</div>`
|
||||||
: html``}
|
: html``}
|
||||||
</div>
|
</div>
|
||||||
${eventCount !== null
|
${eventCount !== null
|
||||||
? html`<div class="right">
|
? html`<div class="right">
|
||||||
@@ -245,9 +245,6 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
@property({ attribute: true })
|
@property({ attribute: true })
|
||||||
public media?: ViewMedia;
|
public media?: ViewMedia;
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
public cameraConfig?: CameraConfig;
|
|
||||||
|
|
||||||
@property({ attribute: true, type: Boolean })
|
@property({ attribute: true, type: Boolean })
|
||||||
public details = false;
|
public details = false;
|
||||||
|
|
||||||
@@ -268,7 +265,7 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
* @returns A template to display to the user.
|
* @returns A template to display to the user.
|
||||||
*/
|
*/
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
if (!this.media || !this.cameraConfig || !this.cameraManager || !this.hass) {
|
if (!this.media || !this.cameraManager || !this.hass) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +290,10 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
this.hass &&
|
this.hass &&
|
||||||
this.cameraManager?.getMediaCapabilities(this.media)?.canFavorite;
|
this.cameraManager?.getMediaCapabilities(this.media)?.canFavorite;
|
||||||
|
|
||||||
const cameraTitle = this.cameraManager.getCameraMetadata(this.hass, this.cameraConfig)?.title;
|
const cameraTitle = this.cameraManager.getCameraMetadata(
|
||||||
|
this.hass,
|
||||||
|
this.media.getCameraID(),
|
||||||
|
)?.title;
|
||||||
|
|
||||||
return html` ${ViewMediaClassifier.isEvent(this.media)
|
return html` ${ViewMediaClassifier.isEvent(this.media)
|
||||||
? html`<frigate-card-thumbnail-feature-event
|
? html`<frigate-card-thumbnail-feature-event
|
||||||
@@ -303,50 +303,50 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
.thumbnail=${thumbnail ?? undefined}
|
.thumbnail=${thumbnail ?? undefined}
|
||||||
></frigate-card-thumbnail-feature-event>`
|
></frigate-card-thumbnail-feature-event>`
|
||||||
: ViewMediaClassifier.isRecording(this.media)
|
: ViewMediaClassifier.isRecording(this.media)
|
||||||
? html`<frigate-card-thumbnail-feature-recording
|
? html`<frigate-card-thumbnail-feature-recording
|
||||||
aria-label="${title ?? ''}"
|
aria-label="${title ?? ''}"
|
||||||
title="${title ?? ''}"
|
title="${title ?? ''}"
|
||||||
.cameraTitle=${this.details ? undefined : cameraTitle}
|
.cameraTitle=${this.details ? undefined : cameraTitle}
|
||||||
.date=${this.media.getStartTime() ?? undefined}
|
.date=${this.media.getStartTime() ?? undefined}
|
||||||
></frigate-card-thumbnail-feature-recording>`
|
></frigate-card-thumbnail-feature-recording>`
|
||||||
: html``}
|
: html``}
|
||||||
${shouldShowFavoriteControl
|
${shouldShowFavoriteControl
|
||||||
? html` <ha-icon
|
? html` <ha-icon
|
||||||
class="${classMap(starClasses)}"
|
class="${classMap(starClasses)}"
|
||||||
icon=${this.media.isFavorite() ? 'mdi:star' : 'mdi:star-outline'}
|
icon=${this.media.isFavorite() ? 'mdi:star' : 'mdi:star-outline'}
|
||||||
title=${localize('thumbnail.retain_indefinitely')}
|
title=${localize('thumbnail.retain_indefinitely')}
|
||||||
@click=${async (ev: Event) => {
|
@click=${async (ev: Event) => {
|
||||||
stopEventFromActivatingCardWideActions(ev);
|
stopEventFromActivatingCardWideActions(ev);
|
||||||
if (this.hass && this.media) {
|
if (this.hass && this.media) {
|
||||||
try {
|
try {
|
||||||
await this.cameraManager?.favoriteMedia(
|
await this.cameraManager?.favoriteMedia(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.media,
|
this.media,
|
||||||
!this.media?.isFavorite(),
|
!this.media?.isFavorite(),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorToConsole(e as Error);
|
errorToConsole(e as Error);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
this.requestUpdate();
|
}}
|
||||||
}
|
|
||||||
}}
|
|
||||||
/></ha-icon>`
|
/></ha-icon>`
|
||||||
: ``}
|
: ``}
|
||||||
${this.details && ViewMediaClassifier.isEvent(this.media)
|
${this.details && ViewMediaClassifier.isEvent(this.media)
|
||||||
? html`<frigate-card-thumbnail-details-event
|
? html`<frigate-card-thumbnail-details-event
|
||||||
.media=${this.media ?? undefined}
|
.media=${this.media ?? undefined}
|
||||||
.seek=${this.seek}
|
.seek=${this.seek}
|
||||||
></frigate-card-thumbnail-details-event>`
|
></frigate-card-thumbnail-details-event>`
|
||||||
: this.details && ViewMediaClassifier.isRecording(this.media)
|
: this.details && ViewMediaClassifier.isRecording(this.media)
|
||||||
? html`<frigate-card-thumbnail-details-recording
|
? html`<frigate-card-thumbnail-details-recording
|
||||||
.media=${this.media ?? undefined}
|
.media=${this.media ?? undefined}
|
||||||
.cameraTitle=${cameraTitle}
|
.cameraTitle=${cameraTitle}
|
||||||
.seek=${this.seek}
|
.seek=${this.seek}
|
||||||
></frigate-card-thumbnail-details-recording>`
|
></frigate-card-thumbnail-details-recording>`
|
||||||
: html``}
|
: html``}
|
||||||
${shouldShowTimelineControl
|
${shouldShowTimelineControl
|
||||||
? html`<ha-icon
|
? html`<ha-icon
|
||||||
class="timeline"
|
class="timeline"
|
||||||
icon="mdi:target"
|
icon="mdi:target"
|
||||||
title=${localize('thumbnail.timeline')}
|
title=${localize('thumbnail.timeline')}
|
||||||
@@ -364,10 +364,9 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
})
|
})
|
||||||
.removeContext('timeline')
|
.removeContext('timeline')
|
||||||
.dispatchChangeEvent(this);
|
.dispatchChangeEvent(this);
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
></ha-icon>`
|
></ha-icon>`
|
||||||
: ''}`;
|
: ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ export class FrigateCardTimelineThumbnail extends LitElement {
|
|||||||
return html` <frigate-card-thumbnail
|
return html` <frigate-card-thumbnail
|
||||||
.hass=${dataRequest.hass}
|
.hass=${dataRequest.hass}
|
||||||
.cameraManager=${dataRequest.cameraManager}
|
.cameraManager=${dataRequest.cameraManager}
|
||||||
.cameraConfig=${dataRequest.cameraConfig}
|
|
||||||
.media=${dataRequest.media}
|
.media=${dataRequest.media}
|
||||||
.view=${dataRequest.view}
|
.view=${dataRequest.view}
|
||||||
?details=${this.details}
|
?details=${this.details}
|
||||||
@@ -259,26 +258,34 @@ export class FrigateCardTimelineCore extends LitElement {
|
|||||||
if (!this.hass || !this.view || !this.timelineConfig) {
|
if (!this.hass || !this.view || !this.timelineConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return html`<div
|
const capabilities = this.cameraManager?.getAggregateCameraCapabilities(
|
||||||
@frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind(
|
this._getTimelineCameraIDs(),
|
||||||
this,
|
);
|
||||||
)}
|
|
||||||
class="timeline"
|
return html` ${capabilities?.supportsTimeline
|
||||||
${ref(this._refTimeline)}
|
? html` <div
|
||||||
>
|
@frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind(
|
||||||
<ha-icon
|
this,
|
||||||
class="lock"
|
)}
|
||||||
.icon=${`mdi:${this._locked ? 'lock' : 'lock-open-variant'}`}
|
class="timeline"
|
||||||
@click=${() => {
|
${ref(this._refTimeline)}
|
||||||
this._locked = !this._locked;
|
>
|
||||||
}}
|
<ha-icon
|
||||||
aria-label="${this._locked
|
class="lock"
|
||||||
? localize('timeline.unlock')
|
.icon=${`mdi:${this._locked ? 'lock' : 'lock-open-variant'}`}
|
||||||
: localize('timeline.lock')}"
|
@click=${() => {
|
||||||
title="${this._locked ? localize('timeline.unlock') : localize('timeline.lock')}"
|
this._locked = !this._locked;
|
||||||
>
|
}}
|
||||||
</ha-icon>
|
aria-label="${this._locked
|
||||||
</div>`;
|
? localize('timeline.unlock')
|
||||||
|
: localize('timeline.lock')}"
|
||||||
|
title="${this._locked
|
||||||
|
? localize('timeline.unlock')
|
||||||
|
: localize('timeline.lock')}"
|
||||||
|
>
|
||||||
|
</ha-icon>
|
||||||
|
</div>`
|
||||||
|
: ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -686,15 +693,10 @@ export class FrigateCardTimelineCore extends LitElement {
|
|||||||
if (!this.hass || !cameraConfig || !this.cameraManager) {
|
if (!this.hass || !cameraConfig || !this.cameraManager) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const cameraMetadata = this.cameraManager.getCameraMetadata(
|
const cameraMetadata = this.cameraManager.getCameraMetadata(this.hass, cameraID);
|
||||||
this.hass,
|
const cameraCapabilities = this.cameraManager.getCameraCapabilities(cameraID);
|
||||||
cameraConfig,
|
|
||||||
);
|
if (cameraMetadata && cameraCapabilities?.supportsTimeline) {
|
||||||
if (
|
|
||||||
cameraMetadata &&
|
|
||||||
cameraConfig.frigate.camera_name &&
|
|
||||||
cameraConfig.frigate.camera_name !== CAMERA_BIRDSEYE
|
|
||||||
) {
|
|
||||||
groups.push({
|
groups.push({
|
||||||
id: cameraID,
|
id: cameraID,
|
||||||
content: cameraMetadata.title,
|
content: cameraMetadata.title,
|
||||||
|
|||||||
Reference in New Issue
Block a user