fix: Don't incorrectly change camera when a dependency supports media (#2171)
- Closes: #2122
This commit is contained in:
@@ -4,7 +4,7 @@ import {
|
||||
capabilityKeys,
|
||||
PTZCapabilities,
|
||||
} from '../types';
|
||||
import { CapabilitySearchOptions } from './types';
|
||||
import { CapabilitySearchKeys } from './types';
|
||||
|
||||
export class Capabilities {
|
||||
private _capabilities: CapabilitiesRaw;
|
||||
@@ -32,7 +32,7 @@ export class Capabilities {
|
||||
delete this._capabilities[capability];
|
||||
}
|
||||
|
||||
public matches(capability: CapabilitySearchOptions): boolean {
|
||||
public matches(capability: CapabilitySearchKeys): boolean {
|
||||
let result = true;
|
||||
if (typeof capability === 'string') {
|
||||
result &&= this.has(capability);
|
||||
|
||||
+54
-25
@@ -4,7 +4,7 @@ import { allPromises } from '../utils/basic';
|
||||
import { ViewMedia } from '../view/item';
|
||||
import { Camera } from './camera';
|
||||
import { CameraManagerEngine } from './engine';
|
||||
import { CapabilitySearchOptions, Engine } from './types';
|
||||
import { CapabilitySearchKeys, CapabilitySearchOptions, Engine } from './types';
|
||||
|
||||
type CameraManagerEngineCameraIDMap = Map<CameraManagerEngine, Set<string>>;
|
||||
|
||||
@@ -27,11 +27,13 @@ export interface CameraManagerReadOnlyConfigStore {
|
||||
getDefaultCameraID(): string | null;
|
||||
|
||||
getCameraIDsWithCapability(
|
||||
capability: CapabilityKey | CapabilitySearchOptions,
|
||||
capability: CapabilitySearchKeys,
|
||||
options?: CapabilitySearchOptions,
|
||||
): Set<string>;
|
||||
getAllDependentCameras(
|
||||
cameraID: string,
|
||||
capability?: CapabilityKey | CapabilitySearchOptions,
|
||||
capability?: CapabilitySearchKeys,
|
||||
options?: CapabilitySearchOptions,
|
||||
): Set<string>;
|
||||
}
|
||||
|
||||
@@ -121,14 +123,23 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore {
|
||||
}
|
||||
|
||||
public getCameraIDsWithCapability(
|
||||
capability: CapabilityKey | CapabilitySearchOptions,
|
||||
capability: CapabilityKey | CapabilitySearchKeys,
|
||||
options?: CapabilitySearchOptions,
|
||||
): Set<string> {
|
||||
const output: Set<string> = new Set();
|
||||
|
||||
for (const camera of this._cameras.values()) {
|
||||
if (camera.getCapabilities()?.matches(capability)) {
|
||||
output.add(camera.getID());
|
||||
}
|
||||
// Must use getAllDependentCameras() to recursively get all relevant
|
||||
// cameras respecting the capabilitiy.
|
||||
// See: https://github.com/dermotduffy/advanced-camera-card/issues/2122
|
||||
|
||||
this.getAllDependentCameras(camera.getID(), capability, options).forEach(
|
||||
(cameraID) => {
|
||||
output.add(cameraID);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -177,33 +188,51 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore {
|
||||
*/
|
||||
public getAllDependentCameras(
|
||||
cameraID: string,
|
||||
capability?: CapabilitySearchOptions,
|
||||
capabilitySearchKeys?: CapabilitySearchKeys,
|
||||
options?: CapabilitySearchOptions,
|
||||
): Set<string> {
|
||||
const visitedCameraIDs = new Set<string>();
|
||||
const matchingCameraIDs: Set<string> = new Set();
|
||||
const getDependentCameras = (cameraID: string): void => {
|
||||
|
||||
const getDependentCameras = (cameraID: string): Set<string> => {
|
||||
visitedCameraIDs.add(cameraID);
|
||||
|
||||
const matchingCameraIDs: Set<string> = new Set();
|
||||
|
||||
const camera = this.getCamera(cameraID);
|
||||
const cameraConfig = camera?.getConfig();
|
||||
|
||||
if (camera && cameraConfig) {
|
||||
if (!capability || camera.getCapabilities()?.matches(capability)) {
|
||||
matchingCameraIDs.add(cameraID);
|
||||
}
|
||||
const dependentCameras: Set<string> = new Set();
|
||||
cameraConfig.dependencies.cameras.forEach((item) => dependentCameras.add(item));
|
||||
if (cameraConfig.dependencies.all_cameras) {
|
||||
this.getCameraIDs().forEach((cameraID) => dependentCameras.add(cameraID));
|
||||
}
|
||||
for (const dependentCameraID of dependentCameras) {
|
||||
if (!visitedCameraIDs.has(dependentCameraID)) {
|
||||
getDependentCameras(dependentCameraID);
|
||||
}
|
||||
if (!camera || !cameraConfig) {
|
||||
return matchingCameraIDs;
|
||||
}
|
||||
|
||||
// Gather all dependent cameras...
|
||||
const dependentCameras: Set<string> = new Set();
|
||||
cameraConfig.dependencies.cameras.forEach((item) => dependentCameras.add(item));
|
||||
if (cameraConfig.dependencies.all_cameras) {
|
||||
this.getCameraIDs().forEach((cameraID) => dependentCameras.add(cameraID));
|
||||
}
|
||||
|
||||
const matchingChildCameraIDs: Set<string> = new Set();
|
||||
|
||||
// ...now recurse through them.
|
||||
for (const dependentCameraID of dependentCameras) {
|
||||
if (!visitedCameraIDs.has(dependentCameraID)) {
|
||||
getDependentCameras(dependentCameraID).forEach((dependentCameraID) =>
|
||||
matchingChildCameraIDs.add(dependentCameraID),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Set([
|
||||
...(!capabilitySearchKeys ||
|
||||
camera.getCapabilities()?.matches(capabilitySearchKeys) ||
|
||||
(options?.inclusive && matchingChildCameraIDs.size)
|
||||
? [cameraID]
|
||||
: []),
|
||||
...matchingChildCameraIDs,
|
||||
]);
|
||||
};
|
||||
getDependentCameras(cameraID);
|
||||
return matchingCameraIDs;
|
||||
|
||||
return getDependentCameras(cameraID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,10 @@ interface CapabilitySearchAllAny {
|
||||
allCapabilities?: CapabilityKey[];
|
||||
anyCapabilities?: CapabilityKey[];
|
||||
}
|
||||
export type CapabilitySearchOptions = CapabilityKey | CapabilitySearchAllAny;
|
||||
export type CapabilitySearchKeys = CapabilityKey | CapabilitySearchAllAny;
|
||||
export interface CapabilitySearchOptions {
|
||||
inclusive?: boolean;
|
||||
}
|
||||
|
||||
export interface CameraManagerCameraMetadata {
|
||||
title: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CapabilitySearchOptions, MediaQuery } from '../../camera-manager/types';
|
||||
import { CapabilitySearchKeys, MediaQuery } from '../../camera-manager/types';
|
||||
import { MEDIA_CHUNK_SIZE_DEFAULT } from '../../const';
|
||||
import { ClipsOrSnapshotsOrAll } from '../../types';
|
||||
import { findBestMediaTimeIndex } from '../../utils/find-best-media-time-index';
|
||||
@@ -27,7 +27,7 @@ export class QueryExecutor {
|
||||
eventsMediaType?: ClipsOrSnapshotsOrAll;
|
||||
executorOptions?: QueryExecutorOptions;
|
||||
}): Promise<QueryExecutorResult | null> {
|
||||
const capabilitySearch: CapabilitySearchOptions =
|
||||
const capabilitySearch: CapabilitySearchKeys =
|
||||
!options?.eventsMediaType || options?.eventsMediaType === 'all'
|
||||
? {
|
||||
anyCapabilities: ['clips', 'snapshots'],
|
||||
|
||||
@@ -11,10 +11,6 @@ export const getCameraIDsForViewName = (
|
||||
viewName: AdvancedCameraCardView,
|
||||
cameraID?: string,
|
||||
): Set<string> => {
|
||||
const capabilityMatchAnyMedia: CapabilitySearchOptions = {
|
||||
anyCapabilities: ['clips', 'snapshots', 'recordings'],
|
||||
};
|
||||
|
||||
switch (viewName) {
|
||||
case 'diagnostics':
|
||||
case 'image':
|
||||
@@ -30,6 +26,9 @@ export const getCameraIDsForViewName = (
|
||||
case 'snapshots':
|
||||
case 'recording':
|
||||
case 'recordings':
|
||||
const options: CapabilitySearchOptions = {
|
||||
inclusive: viewName !== 'live',
|
||||
};
|
||||
const capability =
|
||||
viewName === 'clip'
|
||||
? 'clips'
|
||||
@@ -39,12 +38,12 @@ export const getCameraIDsForViewName = (
|
||||
? 'recordings'
|
||||
: viewName;
|
||||
return cameraID
|
||||
? cameraManager.getStore().getAllDependentCameras(cameraID, capability)
|
||||
: cameraManager.getStore().getCameraIDsWithCapability(capability);
|
||||
? cameraManager.getStore().getAllDependentCameras(cameraID, capability, options)
|
||||
: cameraManager.getStore().getCameraIDsWithCapability(capability, options);
|
||||
|
||||
case 'timeline':
|
||||
return cameraManager
|
||||
.getStore()
|
||||
.getCameraIDsWithCapability(capabilityMatchAnyMedia);
|
||||
return cameraManager.getStore().getCameraIDsWithCapability({
|
||||
anyCapabilities: ['clips', 'snapshots', 'recordings'],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user