Include metadata from recordings.
This commit is contained in:
@@ -48,7 +48,7 @@ import {
|
|||||||
} from './requests';
|
} from './requests';
|
||||||
import orderBy from 'lodash-es/orderBy';
|
import orderBy from 'lodash-es/orderBy';
|
||||||
import throttle from 'lodash-es/throttle';
|
import throttle from 'lodash-es/throttle';
|
||||||
import { allPromises, runWhenIdleIfSupported } from '../../utils/basic';
|
import { allPromises, formatDate, runWhenIdleIfSupported } from '../../utils/basic';
|
||||||
import { fromUnixTime } from 'date-fns';
|
import { fromUnixTime } from 'date-fns';
|
||||||
import { sum } from 'lodash-es';
|
import { sum } from 'lodash-es';
|
||||||
import { FrigateViewMediaClassifier } from './media-classifier';
|
import { FrigateViewMediaClassifier } from './media-classifier';
|
||||||
@@ -127,7 +127,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
|
|||||||
public generateDefaultEventQuery(
|
public generateDefaultEventQuery(
|
||||||
cameras: Map<string, CameraConfig>,
|
cameras: Map<string, CameraConfig>,
|
||||||
cameraIDs: Set<string>,
|
cameraIDs: Set<string>,
|
||||||
query: PartialEventQuery,
|
query?: PartialEventQuery,
|
||||||
): EventQuery[] | null {
|
): EventQuery[] | null {
|
||||||
const relevantCameraConfigs = Array.from(cameraIDs).map((cameraID) =>
|
const relevantCameraConfigs = Array.from(cameraIDs).map((cameraID) =>
|
||||||
cameras.get(cameraID),
|
cameras.get(cameraID),
|
||||||
@@ -172,8 +172,8 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
|
|||||||
public generateDefaultRecordingQuery(
|
public generateDefaultRecordingQuery(
|
||||||
_cameras: Map<string, CameraConfig>,
|
_cameras: Map<string, CameraConfig>,
|
||||||
cameraIDs: Set<string>,
|
cameraIDs: Set<string>,
|
||||||
query: PartialRecordingQuery,
|
query?: PartialRecordingQuery,
|
||||||
): RecordingQuery[] | null {
|
): RecordingQuery[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: QueryType.Recording,
|
type: QueryType.Recording,
|
||||||
@@ -631,7 +631,7 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
|
|||||||
new Set(cameras.keys()),
|
new Set(cameras.keys()),
|
||||||
);
|
);
|
||||||
|
|
||||||
const processQuery = async (
|
const processEventSummary = async (
|
||||||
instanceID: string,
|
instanceID: string,
|
||||||
cameraIDs: Set<string>,
|
cameraIDs: Set<string>,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
@@ -654,9 +654,34 @@ export class FrigateCameraManagerEngine implements CameraManagerEngine {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await allPromises([...instances.entries()], ([instanceID, cameraIDs]) =>
|
const processRecordings = async (
|
||||||
processQuery(instanceID, cameraIDs),
|
cameraIDs: Set<string>): Promise<void> => {
|
||||||
);
|
|
||||||
|
const recordings = await this.getRecordings(hass, cameras, {
|
||||||
|
type: QueryType.Recording,
|
||||||
|
cameraIDs: cameraIDs,
|
||||||
|
});
|
||||||
|
if (!recordings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const result of recordings.values()) {
|
||||||
|
if (!FrigateQueryResultsClassifier.isFrigateRecordingQueryResults(result)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const recording of result.recordings) {
|
||||||
|
// Frigate recordings are always 1 hour long, i.e. never span a day.
|
||||||
|
days.add(formatDate(recording.startTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await allPromises([...instances.entries()], ([instanceID, cameraIDs]) => (async () => {
|
||||||
|
await Promise.all([
|
||||||
|
processEventSummary(instanceID, cameraIDs),
|
||||||
|
processRecordings(cameraIDs)]);
|
||||||
|
})());
|
||||||
|
|
||||||
if (!what.size && !where.size && !days.size) {
|
if (!what.size && !where.size && !days.size) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ export class MediaMetadataController implements ReactiveController {
|
|||||||
if (metadata.days) {
|
if (metadata.days) {
|
||||||
const yearMonths: Set<string> = new Set();
|
const yearMonths: Set<string> = new Set();
|
||||||
[...metadata.days].forEach((day) => {
|
[...metadata.days].forEach((day) => {
|
||||||
// An efficient conversion: 2023-01-26 -> 2023-01
|
// An efficient conversion: "2023-01-26" -> "2023-01"
|
||||||
yearMonths.add(day.substring(0, 7));
|
yearMonths.add(day.substring(0, 7));
|
||||||
});
|
});
|
||||||
const monthStarts: Date[] = [];
|
const monthStarts: Date[] = [];
|
||||||
|
|||||||
@@ -116,6 +116,15 @@ export const formatDateAndTime = (date: Date): string => {
|
|||||||
return format(date, 'yyyy-MM-dd HH:mm');
|
return format(date, 'yyyy-MM-dd HH:mm');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a date object to RFC3339.
|
||||||
|
* @param date A Date object.
|
||||||
|
* @returns A date.
|
||||||
|
*/
|
||||||
|
export const formatDate = (date: Date): string => {
|
||||||
|
return format(date, 'yyyy-MM-dd');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a function in idle periods. If idle callbacks are not supported (e.g.
|
* Run a function in idle periods. If idle callbacks are not supported (e.g.
|
||||||
* Safari) the callback is run immediately.
|
* Safari) the callback is run immediately.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// - TODO: Make media filter slot choice configurable (gallery.ts).
|
// - TODO: Make media filter slot choice configurable (gallery.ts).
|
||||||
// - TODO: Filter panel expands from right can occasionally 'stick' open.
|
// - TODO: Filter panel expands from right can occasionally 'stick' open.
|
||||||
// - TODO: Media type selection, i.e. events or recordings.
|
// - TODO: Media type selection, i.e. events or recordings.
|
||||||
|
// - TODO: Cache every summary.
|
||||||
|
|
||||||
// Hard:
|
// Hard:
|
||||||
// - TODO: Implement gallery.
|
// - TODO: Implement gallery.
|
||||||
|
|||||||
Reference in New Issue
Block a user