diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index d0cdaf99..e4c43492 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -325,7 +325,7 @@ export class FrigateCameraManagerEngine `/api/frigate/${cameraConfig.frigate.client_id}` + `/recording/${cameraConfig.frigate.camera_name}` + `/start/${Math.floor(media.getStartTime().getTime() / 1000)}` + - `/end/${Math.floor(media.getEndTime().getTime() / 1000)}}` + + `/end/${Math.floor(media.getEndTime().getTime() / 1000)}` + `?download=true`, sign: true, }; diff --git a/src/camera-manager/frigate/types.ts b/src/camera-manager/frigate/types.ts index d9ef207d..8c923401 100644 --- a/src/camera-manager/frigate/types.ts +++ b/src/camera-manager/frigate/types.ts @@ -11,7 +11,7 @@ const dayStringToDate = (arg: unknown): Date | unknown => { return typeof arg === 'string' ? dayToDate(arg) : arg; }; -const eventSchema = z.object({ +export const eventSchema = z.object({ camera: z.string(), end_time: z.number().nullable(), false_positive: z.boolean().nullable(), diff --git a/tests/camera-manager/frigate/engine-frigate.test.ts b/tests/camera-manager/frigate/engine-frigate.test.ts new file mode 100644 index 00000000..c0da131c --- /dev/null +++ b/tests/camera-manager/frigate/engine-frigate.test.ts @@ -0,0 +1,134 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { RecordingSegmentsCache, RequestCache } from '../../../src/camera-manager/cache'; +import { FrigateCameraManagerEngine } from '../../../src/camera-manager/frigate/engine-frigate'; +import { + FrigateEventViewMedia, + FrigateRecordingViewMedia, +} from '../../../src/camera-manager/frigate/media'; +import { FrigateEvent, eventSchema } from '../../../src/camera-manager/frigate/types.js'; +import { CameraConfig, RawFrigateCardConfig } from '../../../src/types'; +import { ViewMedia } from '../../../src/view/media'; +import { createCameraConfig, createHASS } from '../../test-utils'; + +const createEngine = (): FrigateCameraManagerEngine => { + return new FrigateCameraManagerEngine( + {}, + new RecordingSegmentsCache(), + new RequestCache(), + ); +}; + +const createRecordingMedia = (): FrigateRecordingViewMedia => { + return new FrigateRecordingViewMedia( + 'recording', + 'camera-1', + { + cameraID: 'camera-1', + startTime: new Date('2023-06-16T20:00:00'), + endTime: new Date('2023-06-16T20:59:59'), + events: 1, + }, + 'recording-id', + 'recording-content-id', + 'recording-title', + ); +}; + +const createEvent = (): FrigateEvent => { + return eventSchema.parse({ + camera: 'camera-1', + end_time: 1686974399, + false_positive: false, + has_clip: true, + has_snapshot: true, + id: 'event-id', + label: 'person', + sub_label: null, + start_time: 1686970800, + top_score: 0.8, + zones: [], + retain_indefinitely: true, + }); +}; + +const createClipMedia = (): FrigateEventViewMedia => { + return new FrigateEventViewMedia( + 'clip', + 'camera-1', + createEvent(), + 'event-clip-content-id', + 'event-clip-thumbnail', + ); +}; + +const createSnapshotMedia = (): FrigateEventViewMedia => { + return new FrigateEventViewMedia( + 'snapshot', + 'camera-1', + createEvent(), + 'event-snapshot-content-id', + 'event-snapshot-thumbnail', + ); +}; + +const createFrigateCameraConfig = (config?: RawFrigateCardConfig): CameraConfig => { + return createCameraConfig({ + frigate: { + camera_name: 'camera-1', + }, + ...config, + }); +}; + +describe('getMediaDownloadPath', () => { + afterEach(() => {}); + + it('should get event with clip download path', async () => { + const endpoint = await createEngine().getMediaDownloadPath( + createHASS(), + createFrigateCameraConfig(), + createClipMedia(), + ); + + expect(endpoint).toEqual({ + endpoint: '/api/frigate/frigate/notifications/event-id/clip.mp4?download=true', + sign: true, + }); + }); + + it('should get event with snapshot download path', async () => { + const endpoint = await createEngine().getMediaDownloadPath( + createHASS(), + createFrigateCameraConfig(), + createSnapshotMedia(), + ); + + expect(endpoint).toEqual({ + endpoint: '/api/frigate/frigate/notifications/event-id/snapshot.jpg?download=true', + sign: true, + }); + }); + + it('should get recording download path', async () => { + const endpoint = await createEngine().getMediaDownloadPath( + createHASS(), + createFrigateCameraConfig(), + createRecordingMedia(), + ); + + expect(endpoint).toEqual({ + endpoint: + '/api/frigate/frigate/recording/camera-1/start/1686970800/end/1686974399?download=true', + sign: true, + }); + }); + + it('should get no path for unknown type', async () => { + const endpoint = await createEngine().getMediaDownloadPath( + createHASS(), + createFrigateCameraConfig(), + new ViewMedia('clip', 'camera-1'), + ); + expect(endpoint).toBeNull(); + }); +});