Generalize camera endpoints.

This commit is contained in:
Dermot Duffy
2023-02-18 11:03:12 -08:00
parent 5767e98501
commit f5ce02fe4a
13 changed files with 219 additions and 132 deletions
+5 -4
View File
@@ -18,9 +18,10 @@ import {
CameraManagerCameraCapabilities,
CameraManagerMediaCapabilities,
CameraManagerCameraMetadata,
CameraURLContext,
CameraEndpointsContext,
CameraConfigs,
Engine,
CameraEndpoints,
} from './types';
export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000;
@@ -118,8 +119,8 @@ export interface CameraManagerEngine {
getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null;
getCameraURL(
getCameraEndpoints(
cameraConfig: CameraConfig,
context?: CameraURLContext,
): string | null;
context?: CameraEndpointsContext,
): CameraEndpoints | null;
}
+85 -39
View File
@@ -36,8 +36,10 @@ import {
RecordingSegment,
RecordingSegmentsQuery,
RecordingSegmentsQueryResultsMap,
CameraURLContext,
CameraEndpointsContext,
CameraConfigs,
CameraEndpoints,
CameraEndpoint,
} from '../types';
import { FrigateRecording } from './types';
import {
@@ -1006,47 +1008,91 @@ export class FrigateCameraManagerEngine
};
}
public getCameraURL(
public getCameraEndpoints(
cameraConfig: CameraConfig,
context?: CameraURLContext,
): string | null {
if (!cameraConfig.frigate.url) {
return null;
}
if (!cameraConfig.frigate.camera_name) {
return cameraConfig.frigate.url;
}
context?: CameraEndpointsContext,
): CameraEndpoints | null {
const getUIEndpoint = (): CameraEndpoint | null => {
if (!cameraConfig.frigate.url) {
return null;
}
if (!cameraConfig.frigate.camera_name) {
return { endpoint: cameraConfig.frigate.url };
}
const eventsURL =
`${cameraConfig.frigate.url}/events?camera=` + cameraConfig.frigate.camera_name;
const recordingsURL =
`${cameraConfig.frigate.url}/recording/` + cameraConfig.frigate.camera_name;
const cameraURL =
`${cameraConfig.frigate.url}/cameras/` + cameraConfig.frigate.camera_name;
// If media is available, use it since it may result in a more precisely
// correct URL.
switch (context?.media?.getMediaType()) {
case 'clip':
case 'snapshot':
return eventsURL;
case 'recording':
const startTime = context.media.getStartTime();
if (startTime) {
return recordingsURL + format(startTime, 'yyyy-MM-dd/HH');
if (context?.view === 'live') {
return { endpoint: cameraURL };
}
const eventsURL =
`${cameraConfig.frigate.url}/events?camera=` + cameraConfig.frigate.camera_name;
const recordingsURL =
`${cameraConfig.frigate.url}/recording/` + cameraConfig.frigate.camera_name;
// If media is available, use it since it may result in a more precisely
// correct URL.
switch (context?.media?.getMediaType()) {
case 'clip':
case 'snapshot':
return { endpoint: eventsURL };
case 'recording':
const startTime = context.media.getStartTime();
if (startTime) {
return { endpoint: recordingsURL + format(startTime, 'yyyy-MM-dd/HH') };
}
}
// Otherwise, fall back to just using the view if we have that.
switch (context?.view) {
case 'clip':
case 'clips':
case 'snapshots':
case 'snapshot':
return { endpoint: eventsURL };
case 'recording':
case 'recordings':
return { endpoint: recordingsURL };
}
return {
endpoint: cameraURL,
};
};
const getGo2RTC = (): CameraEndpoint | null => {
return {
endpoint:
`/api/frigate/${cameraConfig.frigate.client_id}` +
// go2rtc is exposed by the integration under the (slightly
// misleading) 'mse' path, even though that path can serve all go2rtc
// modes.
`/mse/api/ws?src=${cameraConfig.frigate.camera_name}`,
sign: true,
};
};
const getJSMPEG = (): CameraEndpoint | null => {
return {
endpoint:
`/api/frigate/${cameraConfig.frigate.client_id}` +
`/jsmpeg/${cameraConfig.frigate.camera_name}`,
sign: true,
};
};
const ui = getUIEndpoint();
const go2rtc = getGo2RTC();
const jsmpeg = getJSMPEG();
return ui || go2rtc || jsmpeg
? {
...(ui && { ui: ui }),
...(go2rtc && { go2rtc: go2rtc }),
...(jsmpeg && { jsmpeg: jsmpeg }),
}
}
// Otherwise, fall back to just using the view if we have that.
switch (context?.view) {
case 'clip':
case 'clips':
case 'snapshots':
case 'snapshot':
return eventsURL;
case 'recording':
case 'recordings':
return recordingsURL;
}
return `${cameraConfig.frigate.url}/cameras/${cameraConfig.frigate.camera_name}`;
: null;
}
}
+5 -4
View File
@@ -16,12 +16,13 @@ import {
RecordingQueryResultsMap,
RecordingSegmentsQuery,
RecordingSegmentsQueryResultsMap,
CameraURLContext,
CameraEndpointsContext,
CameraConfigs,
RecordingQuery,
QueryReturnType,
CameraManagerCameraCapabilities,
Engine,
CameraEndpoints,
} from '../types';
import { getEntityIcon, getEntityTitle } from '../../utils/ha';
import { EntityRegistryManager } from '../../utils/ha/entity-registry';
@@ -177,10 +178,10 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
return null;
}
public getCameraURL(
public getCameraEndpoints(
_cameraConfig: CameraConfig,
_context?: CameraURLContext,
): string | null {
_context?: CameraEndpointsContext,
): CameraEndpoints | null {
return null;
}
}
+7 -3
View File
@@ -6,7 +6,7 @@ import {
CameraManagerCameraMetadata,
CameraManagerCapabilities,
CameraManagerMediaCapabilities,
CameraURLContext,
CameraEndpointsContext,
DataQuery,
EventQuery,
EventQueryResults,
@@ -29,6 +29,7 @@ import {
RecordingSegmentsQueryResults,
RecordingSegmentsQueryResultsMap,
ResultsMap,
CameraEndpoints,
} from './types.js';
import orderBy from 'lodash-es/orderBy';
import { CameraManagerEngineFactory } from './engine-factory.js';
@@ -643,13 +644,16 @@ export class CameraManager {
);
}
public getCameraURL(cameraID: string, context?: CameraURLContext): string | null {
public getCameraEndpoints(
cameraID: string,
context?: CameraEndpointsContext,
): CameraEndpoints | null {
const cameraConfig = this._store.getCameraConfig(cameraID);
const engine = this._store.getEngineForCameraID(cameraID);
if (!cameraConfig || !engine) {
return null;
}
return engine.getCameraURL(cameraConfig, context);
return engine.getCameraEndpoints(cameraConfig, context);
}
public getCameraMetadata(
+12 -1
View File
@@ -106,11 +106,22 @@ export interface CameraManagerCameraMetadata {
icon: string;
}
export interface CameraURLContext {
export interface CameraEndpointsContext {
media?: ViewMedia;
view?: FrigateCardView;
}
export interface CameraEndpoint {
endpoint: string;
sign?: boolean;
}
export interface CameraEndpoints {
ui?: CameraEndpoint;
go2rtc?: CameraEndpoint;
jsmpeg?: CameraEndpoint;
}
export type CameraConfigs = Map<string, CameraConfig>;
// ===========