Do a fresh media query on snapshot->clip conversion.
This commit is contained in:
+26
-40
@@ -153,6 +153,7 @@ export class FrigateCardViewer extends LitElement {
|
|||||||
this.view,
|
this.view,
|
||||||
{
|
{
|
||||||
targetView: 'media',
|
targetView: 'media',
|
||||||
|
mediaType: mediaType,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -173,6 +174,7 @@ export class FrigateCardViewer extends LitElement {
|
|||||||
.cameras=${this.cameras}
|
.cameras=${this.cameras}
|
||||||
.viewerConfig=${this.viewerConfig}
|
.viewerConfig=${this.viewerConfig}
|
||||||
.resolvedMediaCache=${this.resolvedMediaCache}
|
.resolvedMediaCache=${this.resolvedMediaCache}
|
||||||
|
.cameraManager=${this.cameraManager}
|
||||||
.cardWideConfig=${this.cardWideConfig}
|
.cardWideConfig=${this.cardWideConfig}
|
||||||
>
|
>
|
||||||
</frigate-card-viewer-carousel>
|
</frigate-card-viewer-carousel>
|
||||||
@@ -214,6 +216,9 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public cameras?: Map<string, CameraConfig>;
|
public cameras?: Map<string, CameraConfig>;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public cameraManager?: CameraManager;
|
||||||
|
|
||||||
protected _refMediaCarousel: Ref<FrigateCardMediaCarousel> = createRef();
|
protected _refMediaCarousel: Ref<FrigateCardMediaCarousel> = createRef();
|
||||||
|
|
||||||
protected _carouselOptions?: EmblaOptionsType;
|
protected _carouselOptions?: EmblaOptionsType;
|
||||||
@@ -359,17 +364,16 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a clip view that matches a given snapshot. Includes clips within the
|
* Dispatch a clip view that matches the current (snapshot) query.
|
||||||
* same range as the current view.
|
* @param index The index of the selected media.
|
||||||
* @param snapshot The snapshot to find a matching clip for.
|
|
||||||
* @returns The view that would show the matching clip.
|
|
||||||
*/
|
*/
|
||||||
protected async _createRelatedClipView(targetIndex: number): Promise<View | null> {
|
protected async _dispatchRelatedClipView(index: number): Promise<void> {
|
||||||
const media = this.view?.queryResults?.getResult(targetIndex);
|
const media = this.view?.queryResults?.getResult(index);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.hass ||
|
!this.hass ||
|
||||||
!this.view ||
|
!this.view ||
|
||||||
|
!this.cameraManager ||
|
||||||
!media ||
|
!media ||
|
||||||
// If this specific media item has no clip, then do nothing (even if all
|
// If this specific media item has no clip, then do nothing (even if all
|
||||||
// the other media items do).
|
// the other media items do).
|
||||||
@@ -377,42 +381,28 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
!media.hasClip() ||
|
!media.hasClip() ||
|
||||||
!MediaQueriesClassifier.areEventQueries(this.view.query)
|
!MediaQueriesClassifier.areEventQueries(this.view.query)
|
||||||
) {
|
) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newResults: ViewMedia[] = [];
|
|
||||||
let newSelectedIndex: number | null = null;
|
|
||||||
|
|
||||||
// Convert the query to a clips equivalent.
|
// Convert the query to a clips equivalent.
|
||||||
const newQuery = this.view.query.clone();
|
const clipQuery = this.view.query.clone();
|
||||||
newQuery.convertToClipsQueries();
|
clipQuery.convertToClipsQueries();
|
||||||
|
|
||||||
// Regenerate the whole results stack.
|
const results = await this.cameraManager.executeMediaQuery(this.hass, clipQuery);
|
||||||
for (let i = 0; i < (this.view.queryResults?.getResultsCount() ?? 0); ++i) {
|
if (!results) {
|
||||||
const media = this.view.queryResults?.getResult(i);
|
return;
|
||||||
if (!media || !ViewMediaClassifier.isFrigateEvent(media)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const clipMedia = media.getClipEquivalent();
|
|
||||||
if (clipMedia) {
|
|
||||||
newResults.push(clipMedia);
|
|
||||||
if (i === targetIndex) {
|
|
||||||
newSelectedIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newSelectedIndex === null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const newQueryResults = new MediaQueriesResults(newResults);
|
results.selectResultIfFound((clipMedia) => clipMedia.getID() === media.getID());
|
||||||
newQueryResults.selectResult(newSelectedIndex);
|
if (!results.hasSelectedResult()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return this.view.evolve({
|
this.view.evolve({
|
||||||
view: 'clip',
|
view: 'media',
|
||||||
query: newQuery,
|
query: clipQuery,
|
||||||
queryResults: newQueryResults,
|
queryResults: results,
|
||||||
});
|
}).dispatchChangeEvent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -708,11 +698,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
?.carouselClickAllowed() &&
|
?.carouselClickAllowed() &&
|
||||||
this.viewerConfig?.snapshot_click_plays_clip
|
this.viewerConfig?.snapshot_click_plays_clip
|
||||||
) {
|
) {
|
||||||
this._createRelatedClipView(index).then((view) => {
|
this._dispatchRelatedClipView(index);
|
||||||
if (view) {
|
|
||||||
view.dispatchChangeEvent(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@load="${(e: Event) => {
|
@load="${(e: Event) => {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import format from 'date-fns/format';
|
|||||||
import isEqual from 'lodash-es/isEqual';
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import { FrigateCardError } from '../types';
|
import { FrigateCardError } from '../types';
|
||||||
|
|
||||||
|
export type ModifyInterface<T, R> = Omit<T, keyof R> & R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch a Frigate Card event.
|
* Dispatch a Frigate Card event.
|
||||||
* @param target The target from which send the event.
|
* @param target The target from which send the event.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera/util';
|
|||||||
import { EventMediaQueries } from "../view/media-queries";
|
import { EventMediaQueries } from "../view/media-queries";
|
||||||
import { ViewMedia } from '../view/media';
|
import { ViewMedia } from '../view/media';
|
||||||
import { compressRanges, ExpiringMemoryRangeSet, MemoryRangeSet } from '../camera/range';
|
import { compressRanges, ExpiringMemoryRangeSet, MemoryRangeSet } from '../camera/range';
|
||||||
import { ModifyInterface } from './basic';
|
import { ModifyInterface } from './basic.js';
|
||||||
|
|
||||||
// Allow timeline freshness to be at least this number of seconds out of date
|
// Allow timeline freshness to be at least this number of seconds out of date
|
||||||
// (caching times in the data-engine may increase the effective delay).
|
// (caching times in the data-engine may increase the effective delay).
|
||||||
|
|||||||
+1
-1
@@ -2,11 +2,11 @@
|
|||||||
// - TODO: Callers of all async methods of data-engine need to catch errors.
|
// - TODO: Callers of all async methods of data-engine need to catch errors.
|
||||||
// - TODO: Add garbage collecting of segments not present in the recording summaries anymore.
|
// - TODO: Add garbage collecting of segments not present in the recording summaries anymore.
|
||||||
// - TODO: Do I need to dedup recordings? (i.e. multiple zones on same camera may need to be dedup'd somewhere before returning the view). The media getID() call may be useful for this.
|
// - TODO: Do I need to dedup recordings? (i.e. multiple zones on same camera may need to be dedup'd somewhere before returning the view). The media getID() call may be useful for this.
|
||||||
// - TODO: Do a fresh media query in the viewer on snapshot click, since the first query may (e.g.) only have requested events with snapshots (which would miss an event with just a clip).
|
|
||||||
// - TODO: Move frigate specific view-media under the camera manager.
|
// - TODO: Move frigate specific view-media under the camera manager.
|
||||||
// - TODO: ts-prune https://camchenry.com/blog/deleting-dead-code-in-typescript
|
// - TODO: ts-prune https://camchenry.com/blog/deleting-dead-code-in-typescript
|
||||||
|
|
||||||
// Hard:
|
// Hard:
|
||||||
|
// - TODO: There are circumstances when lazy load doesn't work (e.g. snapshot -> clips re-query)
|
||||||
// - TODO: Implement dragging the timeline seeking forward in both Frigate recordings & events.
|
// - TODO: Implement dragging the timeline seeking forward in both Frigate recordings & events.
|
||||||
// - TODO: Implement gallery.
|
// - TODO: Implement gallery.
|
||||||
// - TODO: Remove FrigateBrowseMediaSource if not necessary (post-gallery).
|
// - TODO: Remove FrigateBrowseMediaSource if not necessary (post-gallery).
|
||||||
|
|||||||
Reference in New Issue
Block a user