Initial version of substream support.
This commit is contained in:
+43
-20
@@ -56,6 +56,18 @@ import { dispatchMessageEvent, dispatchErrorMessageEvent } from '../message.js';
|
||||
import { HassEntity } from 'home-assistant-js-websocket';
|
||||
import { CameraEndpoints } from '../../camera-manager/types.js';
|
||||
|
||||
interface LiveViewContext {
|
||||
// A cameraID override (used for dependencies/substreams to force a different
|
||||
// camera to be live rather than the camera selected in the view).
|
||||
overrides?: Map<string, string>;
|
||||
}
|
||||
|
||||
declare module 'view' {
|
||||
interface ViewContext {
|
||||
live?: LiveViewContext;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state object or dispatch an error. Used in `ha` and `image` live
|
||||
* providers.
|
||||
@@ -339,7 +351,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
}
|
||||
|
||||
protected _getSelectedCameraIndex(): number {
|
||||
const cameraIDs = this.cameraManager?.getCameraIDs();
|
||||
const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs();
|
||||
if (!cameraIDs || !this.view) {
|
||||
return 0;
|
||||
}
|
||||
@@ -362,7 +374,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* @returns A list of EmblaOptionsTypes.
|
||||
*/
|
||||
protected _getPlugins(): EmblaCarouselPlugins {
|
||||
const cameras = this.cameraManager?.getCameraIDs();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameraIDs();
|
||||
return [
|
||||
// Only enable wheel plugin if there is more than one camera.
|
||||
...(cameras && cameras.size > 1
|
||||
@@ -420,18 +432,27 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* name to slide number.
|
||||
*/
|
||||
protected _getSlides(): [TemplateResult[], Record<string, number>] {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!cameras) {
|
||||
const visibleCameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (!visibleCameras) {
|
||||
return [[], {}];
|
||||
}
|
||||
|
||||
const slides: TemplateResult[] = [];
|
||||
const cameraToSlide: Record<string, number> = {};
|
||||
|
||||
for (const [camera, cameraConfig] of cameras) {
|
||||
const slide = this._renderLive(camera, cameraConfig, slides.length);
|
||||
for (const [cameraID, cameraConfig] of visibleCameras) {
|
||||
const liveCameraID =
|
||||
this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
|
||||
const liveCameraConfig =
|
||||
cameraID === liveCameraID
|
||||
? cameraConfig
|
||||
: this.cameraManager?.getStore().getCameraConfig(liveCameraID);
|
||||
|
||||
const slide = liveCameraConfig
|
||||
? this._renderLive(liveCameraID, liveCameraConfig, slides.length)
|
||||
: null;
|
||||
if (slide) {
|
||||
cameraToSlide[camera] = slides.length;
|
||||
cameraToSlide[cameraID] = slides.length;
|
||||
slides.push(slide);
|
||||
}
|
||||
}
|
||||
@@ -442,7 +463,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* Handle the user selecting a new slide in the carousel.
|
||||
*/
|
||||
protected _setViewHandler(ev: CustomEvent<CarouselSelect>): void {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (cameras && ev.detail.index !== this._getSelectedCameraIndex()) {
|
||||
this._setViewCameraID(Array.from(cameras.keys())[ev.detail.index]);
|
||||
}
|
||||
@@ -515,7 +536,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
<frigate-card-live-provider
|
||||
?disabled=${this.liveConfig.lazy_load}
|
||||
.cameraConfig=${cameraConfig}
|
||||
.cameraEndpoints=${guard([this.cameraManager], () =>
|
||||
.cameraEndpoints=${guard([this.cameraManager, cameraID], () =>
|
||||
this.cameraManager?.getCameraEndpoints(cameraID),
|
||||
)}
|
||||
.label=${cameraMetadata?.title ?? ''}
|
||||
@@ -535,7 +556,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
}
|
||||
|
||||
protected _getCameraIDsOfNeighbors(): [string | null, string | null] {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (!cameras || !this.view || !this.hass) {
|
||||
return [null, null];
|
||||
}
|
||||
@@ -557,15 +578,13 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
* @returns A template to display to the user.
|
||||
*/
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.liveConfig || !this.view || !this.hass || !this.cameraManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [slides, cameraToSlide] = this._getSlides();
|
||||
this._cameraToSlide = cameraToSlide;
|
||||
if (
|
||||
!slides.length ||
|
||||
!this.liveConfig ||
|
||||
!this.view ||
|
||||
!this.hass ||
|
||||
!this.cameraManager
|
||||
) {
|
||||
if (!slides.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -577,15 +596,19 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
|
||||
const [prevID, nextID] = this._getCameraIDsOfNeighbors();
|
||||
|
||||
const overrideCameraID = (cameraID: string): string => {
|
||||
return this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
|
||||
};
|
||||
|
||||
const cameraMetadataPrevious = prevID
|
||||
? this.cameraManager.getCameraMetadata(this.hass, prevID)
|
||||
? this.cameraManager.getCameraMetadata(this.hass, overrideCameraID(prevID))
|
||||
: null;
|
||||
const cameraMetadataCurrent = this.cameraManager.getCameraMetadata(
|
||||
this.hass,
|
||||
this.view.camera,
|
||||
overrideCameraID(this.view.camera),
|
||||
);
|
||||
const cameraMetadataNext = nextID
|
||||
? this.cameraManager.getCameraMetadata(this.hass, nextID)
|
||||
? this.cameraManager.getCameraMetadata(this.hass, overrideCameraID(nextID))
|
||||
: null;
|
||||
|
||||
// Notes on the below:
|
||||
|
||||
@@ -31,10 +31,7 @@ import { MediaQueriesClassifier } from '../view/media-queries-classifier';
|
||||
import { View } from '../view/view';
|
||||
import { CameraManager } from '../camera-manager/manager';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import {
|
||||
MediaMetadata,
|
||||
QueryType,
|
||||
} from '../camera-manager/types';
|
||||
import { DataQuery, MediaMetadata, QueryType } from '../camera-manager/types';
|
||||
import format from 'date-fns/format';
|
||||
import endOfMonth from 'date-fns/endOfMonth';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
@@ -168,7 +165,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_ev: CustomEvent<{ value: unknown }>,
|
||||
): Promise<void> {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (!this.hass || !cameras || !this.cameraManager || !this.view) {
|
||||
return;
|
||||
}
|
||||
@@ -269,7 +266,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
if (changedProps.has('cameraManager')) {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (cameras) {
|
||||
this._cameraOptions = Array.from(cameras.keys()).map((cameraID) => ({
|
||||
value: cameraID,
|
||||
@@ -321,7 +318,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
|
||||
protected _getDefaultsFromView(): MediaFilterCoreDefaults | null {
|
||||
const queries = this.view?.query?.getQueries();
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
const cameras = this.cameraManager?.getStore().getVisibleCameras();
|
||||
if (!this.view || !queries || !cameras) {
|
||||
return null;
|
||||
}
|
||||
@@ -333,12 +330,12 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) {
|
||||
let favorite: MediaFilterCoreFavoriteSelection | undefined;
|
||||
|
||||
const cameraIDSets = uniqWith(
|
||||
queries.map((query) => query.cameraIDs),
|
||||
queries.map((query: DataQuery) => query.cameraIDs),
|
||||
isEqual,
|
||||
);
|
||||
// Special note: If all cameras are selected, this is the same as no
|
||||
// Special note: If all visible cameras are selected, this is the same as no
|
||||
// selector at all.
|
||||
if (cameraIDSets.length === 1 && queries[0].cameraIDs.size !== cameras.size) {
|
||||
if (cameraIDSets.length === 1 && isEqual(queries[0].cameraIDs, cameras)) {
|
||||
cameraIDs = [...queries[0].cameraIDs];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { ThumbnailCarouselTap } from './thumbnail-carousel.js';
|
||||
import './surround-basic.js';
|
||||
import { changeViewToRecentEventsForCameraAndDependents } from '../utils/media-to-view';
|
||||
import { getAllDependentCameras } from '../utils/camera.js';
|
||||
import type { DataQuery } from '../camera-manager/types';
|
||||
|
||||
interface ThumbnailViewContext {
|
||||
// Whether or not to fetch thumbnails.
|
||||
@@ -120,7 +121,7 @@ export class FrigateCardSurround extends LitElement {
|
||||
// user is scrubbing video).
|
||||
if (
|
||||
changedProperties.has('view') &&
|
||||
View.isMediaChange(changedProperties.get('view'), this.view)
|
||||
View.isMajorMediaChange(changedProperties.get('view'), this.view)
|
||||
) {
|
||||
this._cameraIDsForTimeline = this._getCameraIDsForTimeline() ?? undefined;
|
||||
}
|
||||
@@ -138,18 +139,20 @@ export class FrigateCardSurround extends LitElement {
|
||||
}
|
||||
|
||||
protected _getCameraIDsForTimeline(): Set<string> | null {
|
||||
const cameras = this.cameraManager?.getCameras();
|
||||
if (!this.view || !cameras) {
|
||||
if (!this.view) {
|
||||
return null;
|
||||
}
|
||||
if (this.view?.is('live')) {
|
||||
return getAllDependentCameras(cameras, this.view.camera);
|
||||
return getAllDependentCameras(
|
||||
this.cameraManager,
|
||||
this.view.camera,
|
||||
);
|
||||
}
|
||||
if (this.view.isViewerView()) {
|
||||
return new Set(
|
||||
this.view.query
|
||||
?.getQueries()
|
||||
?.map((query) => [...query.cameraIDs])
|
||||
?.map((query: DataQuery) => [...query.cameraIDs])
|
||||
.flat(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
const item = request.detail.item;
|
||||
const media = this._timelineSource?.dataset.get(item)?.media;
|
||||
const cameraConfig = media
|
||||
? this.cameraManager?.getCameraConfig(media.getCameraID()) ?? undefined
|
||||
? this.cameraManager?.getStore().getCameraConfigForMedia(media) ?? undefined
|
||||
: undefined;
|
||||
|
||||
request.detail.hass = this.hass;
|
||||
@@ -291,15 +291,9 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
* @returns A set of camera ids (may be empty).
|
||||
*/
|
||||
protected _getTimelineCameraIDs(): Set<string> | null {
|
||||
return this.cameraIDs ?? this._getAllCameraIDs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the keys of all cameras.
|
||||
* @returns A set of camera ids (may be empty).
|
||||
*/
|
||||
protected _getAllCameraIDs(): Set<string> | null {
|
||||
return this.cameraManager?.getCameraIDs() ?? null;
|
||||
return (
|
||||
this.cameraIDs ?? this.cameraManager?.getStore().getVisibleCameraIDs() ?? null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1042,11 +1036,7 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
changedProps.has('cameraIDs')
|
||||
) {
|
||||
const cameraIDs = this._getTimelineCameraIDs();
|
||||
if (
|
||||
cameraIDs &&
|
||||
this.cameraManager &&
|
||||
this.timelineConfig
|
||||
) {
|
||||
if (cameraIDs && this.cameraManager && this.timelineConfig) {
|
||||
this._timelineSource = new TimelineDataSource(
|
||||
this.cameraManager,
|
||||
cameraIDs,
|
||||
|
||||
Reference in New Issue
Block a user