fix: Seek to the start of review media (#2353)

This commit is contained in:
Dermot Duffy
2026-02-16 14:52:11 -08:00
committed by GitHub
parent 282983cbba
commit 7dbf058ab2
2 changed files with 89 additions and 6 deletions
+7 -3
View File
@@ -422,11 +422,8 @@ export class AdvancedCameraCardViewerCarousel extends LitElement {
* Fire a media show event when a slide is selected.
*/
protected async _seekHandler(): Promise<void> {
const view = this.viewManagerEpoch?.manager.getView();
const seek = view?.context?.mediaViewer?.seek;
if (
!this.hass ||
!seek ||
!this._media ||
!this._loadedMediaPlayerController ||
this._selected === null
@@ -438,6 +435,13 @@ export class AdvancedCameraCardViewerCarousel extends LitElement {
return;
}
const view = this.viewManagerEpoch?.manager.getView();
const seek = view?.context?.mediaViewer?.seek ?? selectedMedia.getStartTime();
if (!seek) {
return;
}
const seekTimeInMedia = selectedMedia.includesTime(seek);
setOrRemoveAttribute(this, !seekTimeInMedia, 'unseekable');
if (!seekTimeInMedia && !this._loadedMediaPlayerController.isPaused()) {
@@ -9,11 +9,14 @@ import {
FrigateEventViewMedia,
FrigateRecordingViewMedia,
} from '../../../src/camera-manager/frigate/media';
import { getReviews } from '../../../src/camera-manager/frigate/requests';
import {
getRecordingSegments,
getReviews,
} from '../../../src/camera-manager/frigate/requests';
import {
eventSchema,
FrigateEvent,
FrigateReview,
eventSchema,
} from '../../../src/camera-manager/frigate/types.js';
import { CameraManagerStore } from '../../../src/camera-manager/store';
import { CameraManagerRequestCache, QueryType } from '../../../src/camera-manager/types';
@@ -24,7 +27,7 @@ import { QuerySource } from '../../../src/query-source';
import { Severity } from '../../../src/severity';
import { ViewMedia, ViewMediaType } from '../../../src/view/item';
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
import { createCameraConfig, createHASS } from '../../test-utils';
import { createCameraConfig, createHASS, TestViewMedia } from '../../test-utils';
vi.mock('../../../src/camera-manager/frigate/requests');
@@ -113,6 +116,7 @@ const createFrigateCameraConfig = (
});
};
// @vitest-environment jsdom
describe('getMediaDownloadPath', () => {
it('should get event with clip download path', async () => {
const endpoint = await createEngine().getMediaDownloadPath(
@@ -331,3 +335,78 @@ describe('getReviews', () => {
);
});
});
describe('getMediaSeekTime', () => {
it('should get seek time for review media', async () => {
const engine = createEngine();
const hass = createHASS();
const cameraConfig = createCameraConfig({
frigate: { camera_name: 'camera-1', client_id: 'client-1' },
});
const store = mock<CameraManagerStore>();
store.getCameraConfig.mockReturnValue(cameraConfig);
const startTime = new Date('2023-06-16T20:15:00Z');
const endTime = new Date('2023-06-16T20:45:00Z');
const media = new TestViewMedia({
mediaType: ViewMediaType.Review,
cameraID: 'camera-1',
startTime,
endTime,
});
const segments = [
{
start_time: new Date('2023-06-16T20:00:00Z').getTime() / 1000,
end_time: new Date('2023-06-16T21:00:00Z').getTime() / 1000,
id: 'segment-1',
motion: 0,
objects: 0,
segment_size: 0,
},
];
vi.mocked(getRecordingSegments).mockResolvedValue(segments);
const seekTime = await engine.getMediaSeekTime(hass, store, media, startTime);
// 15 minutes into the hour-long recording.
expect(seekTime).toBe(15 * 60);
});
it('should get zero seek time for clip media when seeking to start', async () => {
const engine = createEngine();
const hass = createHASS();
const cameraConfig = createCameraConfig({
frigate: { camera_name: 'camera-1', client_id: 'client-1' },
});
const store = mock<CameraManagerStore>();
store.getCameraConfig.mockReturnValue(cameraConfig);
const startTime = new Date('2023-06-16T20:15:00Z');
const endTime = new Date('2023-06-16T20:15:10Z');
const media = new TestViewMedia({
mediaType: ViewMediaType.Clip,
cameraID: 'camera-1',
startTime,
endTime,
});
const segments = [
{
start_time: startTime.getTime() / 1000,
end_time: endTime.getTime() / 1000,
id: 'segment-1',
motion: 0,
objects: 0,
segment_size: 0,
},
];
vi.mocked(getRecordingSegments).mockResolvedValue(segments);
const seekTime = await engine.getMediaSeekTime(hass, store, media, startTime);
expect(seekTime).toBe(0);
});
});