Restore initial draft of video seeking.

This commit is contained in:
Dermot Duffy
2023-01-24 19:36:54 -08:00
parent a718e5febe
commit 208795d7b3
5 changed files with 70 additions and 49 deletions
+4
View File
@@ -197,6 +197,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
engine: Engine.Frigate,
events: await getEvents(hass, nativeQuery),
expiry: add(new Date(), { seconds: EVENT_REQUEST_CACHE_MAX_AGE_SECONDS }),
cached: false,
};
}
@@ -257,6 +258,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
expiry: add(new Date(), {
seconds: RECORDING_SUMMARY_REQUEST_CACHE_MAX_AGE_SECONDS,
}),
cached: false,
};
}
@@ -285,6 +287,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
type: QueryResultsType.RecordingSegments,
engine: Engine.Frigate,
segments: cachedSegments,
cached: true,
};
}
@@ -304,6 +307,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
type: QueryResultsType.RecordingSegments,
engine: Engine.Frigate,
segments: segments,
cached: false,
};
}
+8 -5
View File
@@ -210,10 +210,7 @@ export class CameraManager {
orderBy(
// Ensure uniqueness by the ID (if specified), otherwise all elements
// are assumed to be unique.
uniqBy(
mediaArray,
(media) => media.getID() ?? media,
),
uniqBy(mediaArray, (media) => media.getID() ?? media),
// Sort all items leading with the most recent.
(media) => media.getStartTime(),
@@ -315,9 +312,15 @@ export class CameraManager {
result = await engine.getRecordingSegments(hass, this._cameras, query);
}
// The engine may independently cached the results. Respect that in our
// debug logging.
if (result?.cached) {
queryCachedCount++;
}
if (result) {
if (result.expiry) {
this._requestCache.set(query, result, result.expiry);
this._requestCache.set(query, { ...result, cached: true }, result.expiry);
}
results.set(query, result as QueryReturnType<QT>);
}
+1
View File
@@ -45,6 +45,7 @@ export interface QueryResults {
type: QueryResultsType;
engine: Engine;
expiry?: Date;
cached?: boolean;
}
export type QueryReturnType<QT> = QT extends EventQuery
+55 -43
View File
@@ -47,6 +47,7 @@ import { getAllDependentCameras, getCameraTitle } from '../utils/camera.js';
import {
createViewForEvents,
createViewForRecordings,
findClosestMediaIndex,
generateMediaViewerContext,
} from '../utils/media-to-view';
import { CameraManager } from '../camera/manager';
@@ -387,51 +388,66 @@ export class FrigateCardTimelineCore extends LitElement {
* @param properties The range change properties.
* @returns
*/
protected _setViewDuringRangeChange(
_targetTime: Date,
_properties: TimelineRangeChange,
): void {
protected async _setViewDuringRangeChange(
targetTime: Date,
properties: TimelineRangeChange,
): Promise<void> {
const results = this.view?.queryResults;
const media = results?.getResults();
if (
!media ||
!results ||
!this._timeline ||
!this.view ||
// !this.view.target?.length ||
!this.hass ||
!this.cameraManager ||
!this.cameraManager
) {
return;
}
// TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
// const canSeek = !!this.view?.isViewerView();
// const context = canSeek
// ? generateMediaViewerContextForChildren(
// this.cameraManager,
// this.view.target,
// targetTime,
// )
// : null;
const canSeek = !!this.view?.isViewerView();
// const childIndex = this._locked
// ? null
// : findChildIndex(
// this.view.target.children,
// targetTime,
// this._getTimelineCameraIDs(),
// properties.event.additionalEvent === 'panright' ? 'end' : 'start',
// );
const context = canSeek
? await generateMediaViewerContext(
this.hass,
this.cameraManager,
media,
targetTime,
)
: null;
// if (canSeek || (childIndex !== null && childIndex !== this.view.childIndex)) {
// this.view
// .evolve({
// ...(childIndex !== null && {
// childIndex: childIndex,
// }),
// }) // Whether or not to set the timeline window.
// .mergeInContext({
// ...this._generateTimelineContext({ noSetWindow: true }),
// ...context,
// })
// .dispatchChangeEvent(this);
// }
const newResults = this._locked
? null
: results
.clone()
.resetSelectedResult()
.selectBestResult((media) =>
findClosestMediaIndex(
media,
targetTime,
this._getTimelineCameraIDs(),
properties.event.additionalEvent === 'panright' ? 'end' : 'start',
),
);
if (
canSeek ||
(newResults &&
newResults.hasSelectedResult() &&
newResults.getResult() !== results.getResult())
) {
this.view
.evolve({
...(newResults &&
newResults.hasSelectedResult() && { queryResults: newResults }),
}) // Whether or not to set the timeline window.
.mergeInContext({
...this._generateTimelineContext({ noSetWindow: true }),
...context,
})
.dispatchChangeEvent(this);
}
}
/**
@@ -537,9 +553,7 @@ export class FrigateCardTimelineCore extends LitElement {
?.clone()
.resetSelectedResult()
.selectResultIfFound(
(media) =>
!!this.cameras &&
media.getID(this.cameras.get(media.getCameraID())) === properties.item,
(media) => !!this.cameras && media.getID() === properties.item,
),
});
}
@@ -662,9 +676,7 @@ export class FrigateCardTimelineCore extends LitElement {
);
if (options?.selectedItem) {
view.queryResults?.selectResultIfFound(
(media) =>
!!this.cameras &&
media.getID(this.cameras.get(media.getCameraID())) === options.selectedItem,
(media) => !!this.cameras && media.getID() === options.selectedItem,
);
}
return view;
@@ -799,7 +811,7 @@ export class FrigateCardTimelineCore extends LitElement {
}
const media = this.view?.queryResults?.getSelectedResult();
const selectedId = media?.getID(this.cameras.get(media.getCameraID()));
const selectedId = media?.getID();
const firstMedia = (<FrigateCardTimelineItem>first).media;
const secondMedia = (<FrigateCardTimelineItem>second).media;
@@ -810,7 +822,7 @@ export class FrigateCardTimelineCore extends LitElement {
first.type !== 'background' &&
first.type === second.type &&
first.id !== selectedId &&
second.id != selectedId &&
second.id !== selectedId &&
!!firstMedia &&
!!secondMedia &&
ViewMediaClassifier.isEvent(firstMedia) &&
+2 -1
View File
@@ -1,6 +1,7 @@
// Medium:
// Minor / later:
// - TODO: ts-prune https://camchenry.com/blog/deleting-dead-code-in-typescript
// - TODO: getRecordingTitle should use getCameraTitle but need hass.
// - TODO: Pass timezone to recordings & event summary endpoint.
// Hard:
// - TODO: Implement dragging the timeline seeking forward in both Frigate recordings & events.