Initial low performance profile mode.
This commit is contained in:
@@ -4,7 +4,7 @@ import type {
|
||||
RawFrigateCardConfig,
|
||||
} from './types';
|
||||
import { HassEntities } from 'home-assistant-js-websocket';
|
||||
import { cloneDeep, merge } from 'lodash-es';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
export interface ConditionState {
|
||||
view?: string;
|
||||
@@ -109,7 +109,7 @@ export function getOverriddenConfig(
|
||||
overrides: Readonly<RawOverrides> | undefined,
|
||||
conditionState?: Readonly<ConditionState>,
|
||||
): RawFrigateCardConfig {
|
||||
const output = cloneDeep(config);
|
||||
const output = structuredClone(config);
|
||||
let overridden = false;
|
||||
if (overrides) {
|
||||
for (const override of overrides) {
|
||||
|
||||
+6
-2
@@ -101,6 +101,7 @@ import { View } from './view.js';
|
||||
import pkg from '../package.json';
|
||||
import { ViewContext } from 'view';
|
||||
import { DataManager } from './utils/data-manager.js';
|
||||
import { setLowPerformanceProfile } from './performance.js';
|
||||
|
||||
/** A note on media callbacks:
|
||||
*
|
||||
@@ -933,7 +934,10 @@ export class FrigateCard extends LitElement {
|
||||
: localize('error.invalid_configuration_no_hint')),
|
||||
);
|
||||
}
|
||||
const config = parseResult.data;
|
||||
const config =
|
||||
parseResult.data.performance.profile !== 'low'
|
||||
? parseResult.data
|
||||
: setLowPerformanceProfile(inputConfig, parseResult.data);
|
||||
|
||||
if (config.test_gui) {
|
||||
getLovelace().setEditMode(true);
|
||||
@@ -1052,7 +1056,7 @@ export class FrigateCard extends LitElement {
|
||||
}
|
||||
|
||||
if (this._cameras && (changedProps.has('_config') || changedProps.has('_cameras'))) {
|
||||
this._dataManager = new DataManager(this._cameras, this._config.timeline.media);
|
||||
this._dataManager = new DataManager(this._cameras);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
getFullDependentBrowseMediaQueryParametersOrDispatchError,
|
||||
} from '../utils/ha/browse-media';
|
||||
import { changeViewToRecentRecordingForCameraAndDependents } from '../utils/media-to-view.js';
|
||||
import { DataManager } from '../utils/data-manager';
|
||||
import { DataManager } from '../utils/data-manager.js';
|
||||
import { View } from '../view.js';
|
||||
import { renderProgressIndicator } from './message.js';
|
||||
import './thumbnail.js';
|
||||
|
||||
@@ -52,9 +52,9 @@ export class FrigateCardNextPreviousControl extends LitElement {
|
||||
|
||||
const classes = {
|
||||
controls: true,
|
||||
previous: this.direction == 'previous',
|
||||
next: this.direction == 'next',
|
||||
thumbnails: this._controlConfig.style == 'thumbnails',
|
||||
previous: this.direction === 'previous',
|
||||
next: this.direction === 'next',
|
||||
thumbnails: this._controlConfig.style === 'thumbnails',
|
||||
icons: ['chevrons', 'icons'].includes(this._controlConfig.style),
|
||||
button: ['chevrons', 'icons'].includes(this._controlConfig.style),
|
||||
};
|
||||
@@ -62,7 +62,7 @@ export class FrigateCardNextPreviousControl extends LitElement {
|
||||
if (['chevrons', 'icons'].includes(this._controlConfig.style)) {
|
||||
let icon: string;
|
||||
if (this._controlConfig.style === 'chevrons') {
|
||||
icon = this.direction == 'previous' ? 'mdi:chevron-left' : 'mdi:chevron-right';
|
||||
icon = this.direction === 'previous' ? 'mdi:chevron-left' : 'mdi:chevron-right';
|
||||
} else {
|
||||
if (!this.icon) {
|
||||
return html``;
|
||||
|
||||
@@ -84,7 +84,7 @@ export class FrigateCardSurround extends LitElement {
|
||||
this.inBackground ||
|
||||
!this.hass ||
|
||||
!this.view ||
|
||||
this.view.target ||
|
||||
this.view.target ||
|
||||
!this.thumbnailConfig ||
|
||||
this.thumbnailConfig.mode === 'none' ||
|
||||
!this.browseMediaParams ||
|
||||
@@ -200,7 +200,7 @@ export class FrigateCardSurround extends LitElement {
|
||||
>
|
||||
</frigate-card-thumbnail-carousel>`
|
||||
: ''}
|
||||
${this.timelineConfig && !this.inBackground
|
||||
${this.timelineConfig?.mode && this.timelineConfig.mode !== 'none' && !this.inBackground
|
||||
? html` <frigate-card-timeline-core
|
||||
slot=${this.timelineConfig.mode}
|
||||
.hass=${this.hass}
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { cloneDeep, get, isEqual, set } from 'lodash-es';
|
||||
import { get, isEqual, set } from 'lodash-es';
|
||||
import {
|
||||
CONF_CAMERAS,
|
||||
CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
|
||||
@@ -104,7 +104,7 @@ export const upgradeConfig = function (obj: RawFrigateCardConfig): boolean {
|
||||
* @returns `true` if the configuration is upgradeable.
|
||||
*/
|
||||
export const isConfigUpgradeable = function (obj: RawFrigateCardConfig): boolean {
|
||||
const newObj = JSON.parse(JSON.stringify(obj));
|
||||
const newObj = structuredClone(obj);
|
||||
return upgradeConfig(newObj);
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ export const trimConfig = function (obj: RawFrigateCardConfig): boolean {
|
||||
* @returns A new deeply-copied configuration.
|
||||
*/
|
||||
export const copyConfig = function (obj: RawFrigateCardConfig): RawFrigateCardConfig {
|
||||
return cloneDeep(obj);
|
||||
return structuredClone(obj);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -192,7 +192,9 @@ export const CONF_MENU_BUTTONS_FRIGATE_UI = `${CONF_MENU}.buttons.frigate_ui` as
|
||||
export const CONF_MENU_BUTTONS_FULLSCREEN = `${CONF_MENU}.buttons.fullscreen` as const;
|
||||
export const CONF_MENU_BUTTONS_IMAGE = `${CONF_MENU}.buttons.image` as const;
|
||||
export const CONF_MENU_BUTTONS_LIVE = `${CONF_MENU}.buttons.live` as const;
|
||||
export const CONF_MENU_BUTTONS_MEDIA_PLAYER = `${CONF_MENU}.buttons.media_player` as const;
|
||||
export const CONF_MENU_BUTTONS_SNAPSHOTS = `${CONF_MENU}.buttons.snapshots` as const;
|
||||
export const CONF_MENU_BUTTONS_TIMELINE = `${CONF_MENU}.buttons.timeline` as const;
|
||||
|
||||
export const CONF_DIMENSIONS = 'dimensions' as const;
|
||||
export const CONF_DIMENSIONS_ASPECT_RATIO = `${CONF_DIMENSIONS}.aspect_ratio` as const;
|
||||
|
||||
+25
-3
@@ -300,6 +300,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
value: 'none',
|
||||
label: localize('config.common.controls.next_previous.styles.none'),
|
||||
},
|
||||
{
|
||||
value: 'thumbnails',
|
||||
label: localize('config.common.controls.next_previous.styles.thumbnails'),
|
||||
},
|
||||
];
|
||||
|
||||
protected _aspectRatioModes: EditorSelectOption[] = [
|
||||
@@ -912,6 +916,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
domain: string,
|
||||
configPathStyle: string,
|
||||
configPathSize: string,
|
||||
options?: {
|
||||
allowIcons?: boolean;
|
||||
allowThumbnails?: boolean;
|
||||
},
|
||||
): TemplateResult | void {
|
||||
return this._putInSubmenu(
|
||||
domain,
|
||||
@@ -919,9 +927,17 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
'config.common.controls.next_previous.editor_label',
|
||||
{ name: 'mdi:arrow-right-bold-circle' },
|
||||
html`
|
||||
${this._renderOptionSelector(configPathStyle, this._nextPreviousControlStyles, {
|
||||
label: localize('config.common.controls.next_previous.style'),
|
||||
})}
|
||||
${this._renderOptionSelector(
|
||||
configPathStyle,
|
||||
this._nextPreviousControlStyles.filter(
|
||||
(item) =>
|
||||
(!!options?.allowThumbnails || item.value !== 'thumbnails') &&
|
||||
(!!options?.allowIcons || item.value !== 'icons'),
|
||||
),
|
||||
{
|
||||
label: localize('config.common.controls.next_previous.style'),
|
||||
},
|
||||
)}
|
||||
${this._renderNumberInput(configPathSize, {
|
||||
min: BUTTON_SIZE_MIN,
|
||||
label: localize('config.common.controls.next_previous.size'),
|
||||
@@ -1494,6 +1510,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
MENU_LIVE_CONTROLS_NEXT_PREVIOUS,
|
||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
|
||||
{
|
||||
allowIcons: true,
|
||||
},
|
||||
)}
|
||||
${this._renderThumbnailsControls(
|
||||
MENU_LIVE_CONTROLS_THUMBNAILS,
|
||||
@@ -1584,6 +1603,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
MENU_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_SIZE,
|
||||
{
|
||||
allowThumbnails: true,
|
||||
},
|
||||
)}
|
||||
${this._renderThumbnailsControls(
|
||||
MENU_MEDIA_VIEWER_CONTROLS_THUMBNAILS,
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"styles": {
|
||||
"chevrons": "Chevrons",
|
||||
"icons": "Icons",
|
||||
"none": "None"
|
||||
"none": "None",
|
||||
"thumbnails": "Thumbnails"
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
"styles": {
|
||||
"chevrons": "Chevrons",
|
||||
"icons": "Icone",
|
||||
"none": "Icone"
|
||||
"none": "Nessuno",
|
||||
"thumbnails": "Miniature"
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
"styles": {
|
||||
"chevrons": "Setas",
|
||||
"icons": "Ícones",
|
||||
"none": "Nenhum"
|
||||
"none": "Nenhum",
|
||||
"thumbnails": "Miniaturas"
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// TODO: Change defaults themselves?
|
||||
// TODO: Camera auto-dep detection
|
||||
// TODO: CSS
|
||||
// TODO: Renderprogress
|
||||
|
||||
import { deepRemoveDefaults } from './utils/zod.js';
|
||||
import {
|
||||
frigateCardConfigSchema,
|
||||
FrigateCardConfig,
|
||||
RawFrigateCardConfig,
|
||||
} from './types';
|
||||
import { getConfigValue, setConfigValue } from './config-mgmt.js';
|
||||
import {
|
||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
||||
CONF_LIVE_AUTO_MUTE,
|
||||
CONF_LIVE_AUTO_PLAY,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_MODE,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
||||
CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS,
|
||||
CONF_LIVE_CONTROLS_TITLE_MODE,
|
||||
CONF_LIVE_DRAGGABLE,
|
||||
CONF_LIVE_LAZY_UNLOAD,
|
||||
CONF_LIVE_SHOW_IMAGE_DURING_LOAD,
|
||||
CONF_LIVE_TRANSITION_EFFECT,
|
||||
CONF_MEDIA_VIEWER_AUTO_MUTE,
|
||||
CONF_MEDIA_VIEWER_AUTO_PAUSE,
|
||||
CONF_MEDIA_VIEWER_AUTO_PLAY,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE,
|
||||
CONF_MEDIA_VIEWER_DRAGGABLE,
|
||||
CONF_MEDIA_VIEWER_TRANSITION_EFFECT,
|
||||
CONF_MENU_BUTTONS_FRIGATE,
|
||||
CONF_MENU_BUTTONS_MEDIA_PLAYER,
|
||||
CONF_MENU_BUTTONS_TIMELINE,
|
||||
CONF_MENU_STYLE,
|
||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE,
|
||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS,
|
||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
||||
CONF_TIMELINE_SHOW_RECORDINGS,
|
||||
} from './const.js';
|
||||
|
||||
// Caution: These values are applied after parsing (since we cannot know the
|
||||
// performance profile until afterwards), so there is no validation on these
|
||||
// defaults.
|
||||
const LOW_PROFILE_DEFAULTS = {
|
||||
// Disable thumbnail carousels.
|
||||
[CONF_LIVE_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
|
||||
[CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
|
||||
|
||||
// Do not show recordings on timelines.
|
||||
[CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS]: false,
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS]: false,
|
||||
[CONF_TIMELINE_SHOW_RECORDINGS]: false,
|
||||
|
||||
// Take no automatic media actions.
|
||||
[CONF_LIVE_AUTO_PLAY]: 'never' as const,
|
||||
[CONF_LIVE_AUTO_MUTE]: 'never' as const,
|
||||
[CONF_MEDIA_VIEWER_AUTO_PLAY]: 'never' as const,
|
||||
[CONF_MEDIA_VIEWER_AUTO_PAUSE]: 'never' as const,
|
||||
[CONF_MEDIA_VIEWER_AUTO_MUTE]: 'never' as const,
|
||||
|
||||
// Always unload resources that are lazily loaded.
|
||||
[CONF_LIVE_LAZY_UNLOAD]: 'all' as const,
|
||||
|
||||
// Media carousels do not drag.
|
||||
[CONF_LIVE_DRAGGABLE]: false,
|
||||
[CONF_MEDIA_VIEWER_DRAGGABLE]: false,
|
||||
|
||||
// Media carousels have no effects.
|
||||
[CONF_LIVE_TRANSITION_EFFECT]: 'none' as const,
|
||||
[CONF_MEDIA_VIEWER_TRANSITION_EFFECT]: 'none' as const,
|
||||
|
||||
// Do not show image during load.
|
||||
[CONF_LIVE_SHOW_IMAGE_DURING_LOAD]: false,
|
||||
|
||||
// Media player next/previous are chevrons.
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE]: 'chevrons' as const,
|
||||
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE]: 'none' as const,
|
||||
[CONF_LIVE_CONTROLS_TITLE_MODE]: 'none' as const,
|
||||
|
||||
// Move the menu to outside to remove the need to interact with it with open.
|
||||
[CONF_MENU_STYLE]: 'outside',
|
||||
|
||||
// Hide several buttons that are otherwise visible by default.
|
||||
[`${CONF_MENU_BUTTONS_FRIGATE}.enabled`]: false,
|
||||
[`${CONF_MENU_BUTTONS_TIMELINE}.enabled`]: false,
|
||||
[`${CONF_MENU_BUTTONS_MEDIA_PLAYER}.enabled`]: false,
|
||||
[`${CONF_MENU_BUTTONS_TIMELINE}.enabled`]: false,
|
||||
|
||||
// Disable all options in thumbnails.
|
||||
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
|
||||
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
|
||||
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
|
||||
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
|
||||
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
|
||||
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
|
||||
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
|
||||
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
|
||||
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
|
||||
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Set low performance profile mode. Sets flags as defined in
|
||||
* LOW_PROFILE_DEFAULTS unless they are explicitly overriden in the
|
||||
* configuration.
|
||||
* @param inputConfig The raw unparsed input configuration.
|
||||
* @param parsedConfig The parsed input configuration.
|
||||
* @returns A changed (in-place) parsed input configuration.
|
||||
*/
|
||||
export const setLowPerformanceProfile = (
|
||||
inputConfig: RawFrigateCardConfig,
|
||||
parsedConfig: FrigateCardConfig,
|
||||
): FrigateCardConfig => {
|
||||
const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse(
|
||||
inputConfig,
|
||||
);
|
||||
if (defaultLessParseResult.success) {
|
||||
const defaultLessConfig = defaultLessParseResult.data;
|
||||
Object.entries(LOW_PROFILE_DEFAULTS).forEach(([k, v]: [string, unknown]) => {
|
||||
if (getConfigValue(defaultLessConfig, k) === undefined) {
|
||||
setConfigValue(parsedConfig, k, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
return parsedConfig;
|
||||
};
|
||||
@@ -1206,6 +1206,14 @@ const liveOverridesSchema = z
|
||||
.optional();
|
||||
export type LiveOverrides = z.infer<typeof liveOverridesSchema>;
|
||||
|
||||
const performanceConfigDefault = {
|
||||
profile: 'high' as const,
|
||||
}
|
||||
|
||||
const performanceConfigSchema = z.object({
|
||||
profile: z.enum(['low', 'high'])
|
||||
}).default(performanceConfigDefault);
|
||||
|
||||
/**
|
||||
* Main card config.
|
||||
*/
|
||||
@@ -1221,6 +1229,7 @@ export const frigateCardConfigSchema = z.object({
|
||||
elements: pictureElementsSchema,
|
||||
dimensions: dimensionsConfigSchema,
|
||||
timeline: timelineConfigSchema,
|
||||
performance: performanceConfigSchema,
|
||||
|
||||
// Configuration overrides.
|
||||
overrides: overridesSchema,
|
||||
@@ -1246,6 +1255,7 @@ export const frigateCardConfigDefaults = {
|
||||
image: imageConfigDefault,
|
||||
timeline: timelineConfigDefault,
|
||||
mini_timeline: timelineCoreConfigDefault,
|
||||
performance: performanceConfigDefault,
|
||||
};
|
||||
|
||||
const menuButtonSchema = z.discriminatedUnion('type', [
|
||||
|
||||
@@ -104,7 +104,6 @@ export class DataManager {
|
||||
protected _maxAgeSeconds: number = DATA_MANAGER_MAX_AGE_SECONDS;
|
||||
|
||||
protected _cameras: Map<string, CameraConfig>;
|
||||
protected _mediaType: TimelineMediaType;
|
||||
|
||||
// Garbage collect segments at most once an hour.
|
||||
protected _throttledSegmentGarbageCollector = throttle(
|
||||
@@ -115,9 +114,8 @@ export class DataManager {
|
||||
{ trailing: true },
|
||||
);
|
||||
|
||||
constructor(cameras: Map<string, CameraConfig>, mediaType: TimelineMediaType) {
|
||||
constructor(cameras: Map<string, CameraConfig>) {
|
||||
this._cameras = cameras;
|
||||
this._mediaType = mediaType;
|
||||
}
|
||||
|
||||
// Get the last event fetch date.
|
||||
|
||||
Reference in New Issue
Block a user